From b9a31d78dd6a6e86bc01d49bf48d14ca41f11c2c Mon Sep 17 00:00:00 2001 From: hniksic Date: Tue, 22 Mar 2005 05:20:02 -0800 Subject: [PATCH] [svn] Support human-readable file size printing. Don't use persistent connection over proxies. --- src/ChangeLog | 18 +++++++++ src/ftp-ls.c | 2 +- src/ftp.c | 33 +++++++++++------ src/http.c | 26 +++++++++++-- src/main.c | 4 +- src/progress.c | 4 +- src/sysdep.h | 4 +- src/utils.c | 99 +++++++++++++++++++++++++++++++++++++++++--------- src/utils.h | 5 ++- 9 files changed, 155 insertions(+), 40 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 5160c558..d306c41b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,21 @@ +2005-03-21 Hrvoje Niksic + + * http.c (gethttp): Print the human-readable size. + + * ftp.c (getftp): Print the human-readable size of the file to be + downloaded. + + * utils.c (human_readable): New function. + + * utils.c: Renamed "legible" to "with_thousand_seps", + "legible_large_int" to "with_thousand_seps_large", and "legible_1" + to "add_thousand_seps". + +2005-03-21 Hrvoje Niksic + + * http.c (gethttp): Inhibit persistent connections when talking to + proxies, as mandated by RFC 2068. + 2005-03-20 Hrvoje Niksic * url.c (unescape_single_char): New function. diff --git a/src/ftp-ls.c b/src/ftp-ls.c index 71d8e837..91330250 100644 --- a/src/ftp-ls.c +++ b/src/ftp-ls.c @@ -939,7 +939,7 @@ ftp_index (const char *file, struct url *u, struct fileinfo *f) putc ('/', fp); fprintf (fp, " "); if (f->type == FT_PLAINFILE) - fprintf (fp, _(" (%s bytes)"), legible (f->size)); + fprintf (fp, _(" (%s bytes)"), with_thousand_seps (f->size)); else if (f->type == FT_SYMLINK) fprintf (fp, "-> %s", f->linkto ? f->linkto : "(nil)"); putc ('\n', fp); diff --git a/src/ftp.c b/src/ftp.c index d2e031e7..e138896c 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -220,6 +220,26 @@ ftp_do_port (int csock, int *local_sock) } #endif +static void +print_length (wgint size, wgint start, int authoritative) +{ + logprintf (LOG_VERBOSE, _("Length: %s"), with_thousand_seps (size)); + if (size >= 1024) + logprintf (LOG_VERBOSE, " (%s)", human_readable (size)); + if (start > 0) + { + if (start >= 1024) + logprintf (LOG_VERBOSE, _(", %s (%s) remaining"), + with_thousand_seps (size - start), + human_readable (size - start)); + else + logprintf (LOG_VERBOSE, _(", %s remaining"), + with_thousand_seps (size - start)); + } + if (!authoritative) + logputs (LOG_VERBOSE, _(" (unauthoritative)\n")); +} + /* Retrieves a file with denoted parameters through opening an FTP connection to the server. It always closes the data connection, and closes the control connection in case of error. */ @@ -993,20 +1013,11 @@ Error in server response, closing control connection.\n")); if (*len) { - logprintf (LOG_VERBOSE, _("Length: %s"), legible (*len)); - if (restval) - logprintf (LOG_VERBOSE, _(" [%s to go]"), legible (*len - restval)); - logputs (LOG_VERBOSE, "\n"); + print_length (*len, restval, 1); expected_bytes = *len; /* for get_contents/show_progress */ } else if (expected_bytes) - { - logprintf (LOG_VERBOSE, _("Length: %s"), legible (expected_bytes)); - if (restval) - logprintf (LOG_VERBOSE, _(" [%s to go]"), - legible (expected_bytes - restval)); - logputs (LOG_VERBOSE, _(" (unauthoritative)\n")); - } + print_length (expected_bytes, restval, 0); /* Get the contents of the document. */ flags = 0; diff --git a/src/http.c b/src/http.c index d66b28ff..85d73404 100644 --- a/src/http.c +++ b/src/http.c @@ -1089,8 +1089,15 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) is done. */ int keep_alive; - /* Whether keep-alive should be inhibited. */ - int inhibit_keep_alive = !opt.http_keep_alive || opt.ignore_length; + /* Whether keep-alive should be inhibited. + + RFC 2068 requests that 1.0 clients not send keep-alive requests + to proxies. This is because many 1.0 proxies do not interpret + the Connection header and transfer it to the remote server, + causing it to not close the connection and leave both the proxy + and the client hanging. */ + int inhibit_keep_alive = + !opt.http_keep_alive || opt.ignore_length /*|| proxy != NULL*/; /* Headers sent when using POST. */ wgint post_data_size = 0; @@ -1733,9 +1740,20 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) logputs (LOG_VERBOSE, _("Length: ")); if (contlen != -1) { - logputs (LOG_VERBOSE, legible (contlen + contrange)); + logputs (LOG_VERBOSE, with_thousand_seps (contlen + contrange)); + if (contlen + contrange >= 1024) + logprintf (LOG_VERBOSE, " (%s)", + human_readable (contlen + contrange)); if (contrange) - logprintf (LOG_VERBOSE, _(" (%s to go)"), legible (contlen)); + { + if (contlen >= 1024) + logprintf (LOG_VERBOSE, _(", %s (%s) remaining"), + with_thousand_seps (contlen), + human_readable (contlen)); + else + logprintf (LOG_VERBOSE, _(", %s remaining"), + with_thousand_seps (contlen)); + } } else logputs (LOG_VERBOSE, diff --git a/src/main.c b/src/main.c index 432c7d48..065d215a 100644 --- a/src/main.c +++ b/src/main.c @@ -943,13 +943,13 @@ Can't timestamp and not clobber old files at the same time.\n")); { logprintf (LOG_NOTQUIET, _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"), - time_str (NULL), legible_large_int (total_downloaded_bytes), + time_str (NULL), with_thousand_seps_large (total_downloaded_bytes), opt.numurls); /* Print quota warning, if exceeded. */ if (opt.quota && total_downloaded_bytes > opt.quota) logprintf (LOG_NOTQUIET, _("Download quota (%s bytes) EXCEEDED!\n"), - legible (opt.quota)); + with_thousand_seps_large (opt.quota)); } if (opt.cookies_output) diff --git a/src/progress.c b/src/progress.c index 3da69852..2c6b5820 100644 --- a/src/progress.c +++ b/src/progress.c @@ -721,7 +721,7 @@ create_image (struct bar_progress *bp, double dl_total_time) char *p = bp->buffer; wgint size = bp->initial_length + bp->count; - char *size_legible = legible (size); + char *size_legible = with_thousand_seps (size); int size_legible_len = strlen (size_legible); struct bar_progress_hist *hist = &bp->hist; @@ -828,7 +828,7 @@ create_image (struct bar_progress *bp, double dl_total_time) } /* " 234,567,890" */ - sprintf (p, " %-11s", legible (size)); + sprintf (p, " %-11s", with_thousand_seps (size)); p += strlen (p); /* " 1012.45K/s" */ diff --git a/src/sysdep.h b/src/sysdep.h index 2aaa757d..e93f257e 100644 --- a/src/sysdep.h +++ b/src/sysdep.h @@ -111,7 +111,9 @@ so, delete this exception statement from your version. */ /* Define a large integral type useful for storing large sizes that exceed sizes of one download, such as when printing the sum of all downloads. Note that this has nothing to do with large file - support, which determines the wgint type. + support, which determines the wgint type. This should be as large + as possible even on systems where when wgint is 32-bit; also, + unlike wgint, this can be a floating point type. We use a 64-bit integral type where available, `double' otherwise. It's hard to print LARGE_INT's portably, but fortunately it's diff --git a/src/utils.c b/src/utils.c index eace57c3..2e8524ed 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1226,11 +1226,11 @@ free_keys_and_values (struct hash_table *ht) } -/* Engine for legible and legible_large_int; add thousand separators - to numbers printed in strings. */ +/* Add thousand separators to a number already in string form. Used + by with_thousand_seps and with_thousand_seps_large. */ static char * -legible_1 (const char *repr) +add_thousand_seps (const char *repr) { static char outbuf[48]; int i, i1, mod; @@ -1266,41 +1266,106 @@ legible_1 (const char *repr) return outbuf; } -/* Legible -- return a static pointer to the legibly printed wgint. */ +/* Return a static pointer to the number printed with thousand + separators inserted at the right places. */ char * -legible (wgint l) +with_thousand_seps (wgint l) { char inbuf[24]; /* Print the number into the buffer. */ number_to_string (inbuf, l); - return legible_1 (inbuf); + return add_thousand_seps (inbuf); } /* Write a string representation of LARGE_INT NUMBER into the provided - buffer. The buffer should be able to accept 24 characters, - including the terminating zero. + buffer. It would be dangerous to use sprintf, because the code wouldn't work on a machine with gcc-provided long long support, but without - libc support for "%lld". However, such platforms will typically - not have snprintf and will use our version, which does support - "%lld" where long longs are available. */ + libc support for "%lld". However, such old systems platforms + typically lack snprintf and will end up using our version, which + does support "%lld" whereever long longs are available. */ static void -large_int_to_string (char *buffer, LARGE_INT number) +large_int_to_string (char *buffer, int bufsize, LARGE_INT number) { - snprintf (buffer, 24, LARGE_INT_FMT, number); + snprintf (buffer, bufsize, LARGE_INT_FMT, number); } -/* The same as legible(), but works on LARGE_INT. */ +/* The same as with_thousand_seps, but works on LARGE_INT. */ char * -legible_large_int (LARGE_INT l) +with_thousand_seps_large (LARGE_INT l) { char inbuf[48]; - large_int_to_string (inbuf, l); - return legible_1 (inbuf); + large_int_to_string (inbuf, sizeof (inbuf), l); + return add_thousand_seps (inbuf); +} + +/* N, a byte quantity, is converted to a human-readable abberviated + form a la sizes printed by `ls -lh'. The result is written to a + static buffer, a pointer to which is returned. + + Unlike `with_thousand_seps', this approximates to the nearest unit. + Quoting GNU libit: "Most people visually process strings of 3-4 + digits effectively, but longer strings of digits are more prone to + misinterpretation. Hence, converting to an abbreviated form + usually improves readability." + + This intentionally uses kilobyte (KB), megabyte (MB), etc. in their + original computer science meaning of "multiples of 1024". + Multiples of 1000 would be useless since Wget already adds thousand + separators for legibility. We don't use the "*bibyte" names + invented in 1998, and seldom used in practice. Wikipedia's entry + on kilobyte discusses this in some detail. */ + +char * +human_readable (wgint n) +{ + /* These suffixes are compatible with those of GNU `ls -lh'. */ + static char powers[] = + { + 'K', /* kilobyte, 2^10 bytes */ + 'M', /* megabyte, 2^20 bytes */ + 'G', /* gigabyte, 2^30 bytes */ + 'T', /* terabyte, 2^40 bytes */ + 'P', /* petabyte, 2^50 bytes */ + 'E', /* exabyte, 2^60 bytes */ + }; + static char buf[8]; + int i; + + /* If the quantity is smaller than 1K, just print it. */ + if (n < 1024) + { + snprintf (buf, sizeof (buf), "%d", (int) n); + return buf; + } + + /* Loop over powers, dividing N with 1024 in each iteration. This + works unchanged for all sizes of wgint, while still avoiding + non-portable `long double' arithmetic. */ + for (i = 0; i < countof (powers); i++) + { + /* At each iteration N is greater than the *subsequent* power. + That way N/1024.0 produces a decimal number in the units of + *this* power. */ + if ((n >> 10) < 1024 || i == countof (powers) - 1) + { + /* Must cast to long first because MS VC can't directly cast + __int64 to double. (This is safe because N is known to + be <2**20.) */ + double val = (double) (long) n / 1024.0; + /* Print values smaller than 10 with one decimal digits, and + others without any decimals. */ + snprintf (buf, sizeof (buf), "%.*f%c", + val < 10 ? 1 : 0, val, powers[i]); + return buf; + } + n >>= 10; + } + return NULL; /* unreached */ } /* Count the digits in an integer number. */ diff --git a/src/utils.h b/src/utils.h index 1b3da628..5845f80f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -112,8 +112,9 @@ int string_set_contains PARAMS ((struct hash_table *, const char *)); void string_set_free PARAMS ((struct hash_table *)); void free_keys_and_values PARAMS ((struct hash_table *)); -char *legible PARAMS ((wgint)); -char *legible_large_int PARAMS ((LARGE_INT)); +char *with_thousand_seps PARAMS ((wgint)); +char *with_thousand_seps_large PARAMS ((LARGE_INT)); +char *human_readable PARAMS ((wgint)); int numdigit PARAMS ((wgint)); char *number_to_string PARAMS ((char *, wgint)); char *number_to_static_string PARAMS ((wgint)); -- 2.39.2