From db07b5906742c916e9d2eb09276d7f5eeb2b17b6 Mon Sep 17 00:00:00 2001
From: Maciek Borzecki <maciek.borzecki@gmail.com>
Date: Sun, 4 Oct 2009 20:14:39 +0200
Subject: [PATCH] wget: add support for dotted progress indicator

---
 include/usage.h   |    6 +-
 networking/wget.c |  159 +++++++++++++++++++++++++++++++++++------------------
 2 files changed, 109 insertions(+), 56 deletions(-)

diff --git a/include/usage.h b/include/usage.h
index 9b9a56f..f703ce5 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -4971,10 +4971,10 @@ IF_FEATURE_TUNCTL_UG( \
 	IF_FEATURE_WGET_LONG_OPTIONS( \
        "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document file]\n" \
        "	[--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n" \
-       "	[-U|--user-agent agent] url" \
+       "	[-U|--user-agent agent]" IF_FEATURE_WGET_STATUSBAR(" [-d|--dot]") " url" \
 	) \
 	IF_NOT_FEATURE_WGET_LONG_OPTIONS( \
-       "[-csq] [-O file] [-Y on/off] [-P DIR] [-U agent] url" \
+       "[-csq] [-O file] [-Y on/off] [-P DIR] [-U agent]" IF_FEATURE_WGET_STATUSBAR(" [-d]") " url" \
 	)
 #define wget_full_usage "\n\n" \
        "Retrieve files via HTTP or FTP\n" \
@@ -4982,6 +4982,8 @@ IF_FEATURE_TUNCTL_UG( \
      "\n	-s	Spider mode - only check file existence" \
      "\n	-c	Continue retrieval of aborted transfer" \
      "\n	-q	Quiet" \
+	IF_FEATURE_WGET_STATUSBAR( \
+     "\n        -d      Use \'dot\' progress bar") \
      "\n	-P	Set directory prefix to DIR" \
      "\n	-O	Save to filename ('-' for stdout)" \
      "\n	-U	Adjust 'User-Agent' field" \
diff --git a/networking/wget.c b/networking/wget.c
index b8cd549..cf0dc26 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -30,6 +30,7 @@ struct globals {
 	const char *curfile;      /* Name of current file being transferred */
 	unsigned lastupdate_sec;
 	unsigned start_sec;
+	int use_dot;
 #endif
 	smallint chunked;         /* chunked transfer encoding */
 	smallint got_clen;        /* got content-length: from server  */
@@ -46,10 +47,14 @@ struct BUG_G_too_big {
 #define curfile         (G.curfile        )
 #define lastupdate_sec  (G.lastupdate_sec )
 #define start_sec       (G.start_sec      )
+#define use_dot         (G.use_dot        )
 #define INIT_G() do { } while (0)
 
 
 #if ENABLE_FEATURE_WGET_STATUSBAR
+
+#define ETA(__total, __transferred, __elapsed) \
+	((unsigned long long)__total * __elapsed / __transferred - __elapsed)
 enum {
 	STALLTIME = 5                   /* Seconds when xfer considered "stalled" */
 };
@@ -69,6 +74,7 @@ static void progress_meter(int flag)
 	unsigned since_last_update, elapsed;
 	unsigned ratio;
 	int barlength, i;
+	off_t to_download;
 
 	if (flag == -1) { /* first call to progress_meter */
 		start_sec = monotonic_sec();
@@ -84,69 +90,104 @@ static void progress_meter(int flag)
 		if (ratio > 100) ratio = 100;
 	}
 
-	fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio);
-
-	barlength = get_tty2_width() - 49;
-	if (barlength > 0) {
-		/* god bless gcc for variable arrays :) */
-		i = barlength * ratio / 100;
-		{
-			char buf[i+1];
-			memset(buf, '*', i);
-			buf[i] = '\0';
-			fprintf(stderr, "|%s%*s|", buf, barlength - i, "");
-		}
-	}
-	i = 0;
-	abbrevsize = transferred + beg_range;
-	while (abbrevsize >= 100000) {
-		i++;
-		abbrevsize >>= 10;
-	}
-	/* see http://en.wikipedia.org/wiki/Tera */
-	fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]);
-
-// Nuts! Ain't it easier to update progress meter ONLY when we transferred++?
-
 	elapsed = monotonic_sec();
-	since_last_update = elapsed - lastupdate_sec;
-	if (transferred > lastsize) {
-		lastupdate_sec = elapsed;
-		lastsize = transferred;
-		if (since_last_update >= STALLTIME) {
-			/* We "cut off" these seconds from elapsed time
-			 * by adjusting start time */
-			start_sec += since_last_update;
+	to_download = totalsize - beg_range;
+
+	if (use_dot == 1) {
+		unsigned lastsize_k = lastsize >> 10;
+		elapsed -= start_sec;
+
+		if (transferred != to_download) { /* still downloading */
+			while ((transferred - lastsize) > 1024 ) {
+				if (lastsize_k % 50 == 0)  {
+					since_last_update = elapsed - lastupdate_sec;
+					if (lastsize_k > 0) {
+						/* ETA calculated exactly the same */
+						int eta = (int) ETA(to_download, transferred, elapsed);
+						fprintf(stderr, "%3d%% %ds\n", ratio, eta);
+					}
+					fprintf(stderr, "%6dK ", 50 * (lastsize_k / 50));
+					lastupdate_sec = elapsed;
+				} else {
+					if (lastsize_k % 10 == 0)
+						fputc(' ', stderr);
+				}
+				fputc('.', stderr);
+				lastsize += 1024;
+			}
+		} else if (flag != 0) { /* downloaded the file */
+			unsigned lastsize_fill = ((lastsize >> 10) + 1) << 10;
+			while (lastsize < lastsize_fill) {
+				fputc(' ', stderr);
+				lastsize += 1024;
+			}
+			fprintf(stderr, "%d%% %ds\n", ratio, elapsed);
 		}
-		since_last_update = 0; /* we are un-stalled now */
-	}
-	elapsed -= start_sec; /* now it's "elapsed since start" */
 
-	if (since_last_update >= STALLTIME) {
-		fprintf(stderr, " - stalled -");
 	} else {
-		off_t to_download = totalsize - beg_range;
-		if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || G.chunked) {
-			fprintf(stderr, "--:--:-- ETA");
+		fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio);
+
+		barlength = get_tty2_width() - 49;
+		if (barlength > 0) {
+			/* god bless gcc for variable arrays :) */
+			i = barlength * ratio / 100;
+			{
+				char buf[i+1];
+				memset(buf, '*', i);
+				buf[i] = '\0';
+				fprintf(stderr, "|%s%*s|", buf, barlength - i, "");
+			}
+		}
+		i = 0;
+		abbrevsize = transferred + beg_range;
+		while (abbrevsize >= 100000) {
+			i++;
+			abbrevsize >>= 10;
+		}
+		/* see http://en.wikipedia.org/wiki/Tera */
+		fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]);
+
+		// Nuts! Ain't it easier to update progress meter ONLY when we transferred++?
+
+		since_last_update = elapsed - lastupdate_sec;
+		if (transferred > lastsize) {
+			lastupdate_sec = elapsed;
+			lastsize = transferred;
+			if (since_last_update >= STALLTIME) {
+				/* We "cut off" these seconds from elapsed time
+				 * by adjusting start time */
+				start_sec += since_last_update;
+			}
+			since_last_update = 0; /* we are un-stalled now */
+		}
+		elapsed -= start_sec; /* now it's "elapsed since start" */
+
+		if (since_last_update >= STALLTIME) {
+			fprintf(stderr, " - stalled -");
 		} else {
-			/* to_download / (transferred/elapsed) - elapsed: */
-			int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed);
-			/* (long long helps to have working ETA even if !LFS) */
-			i = eta % 3600;
-			fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
+			if (transferred <= 0 || (int)elapsed <= 0 || transferred > to_download || G.chunked) {
+				fprintf(stderr, "--:--:-- ETA");
+			} else {
+				/* to_download / (transferred/elapsed) - elapsed: */
+				int eta = (int) ETA(to_download, transferred, elapsed);
+				/* (long long helps to have working ETA even if !LFS) */
+				i = eta % 3600;
+				fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60);
+			}
 		}
 	}
-
 	if (flag == 0) {
 		/* last call to progress_meter */
 		alarm(0);
 		transferred = 0;
 		fputc('\n', stderr);
 	} else {
-		if (flag == -1) { /* first call to progress_meter */
-			signal_SA_RESTART_empty_mask(SIGALRM, progress_meter);
+		if (use_dot == 0) {
+			if (flag == -1) { /* first call to progress_meter */
+				signal_SA_RESTART_empty_mask(SIGALRM, progress_meter);
+			}
+			alarm(1);
 		}
-		alarm(1);
 	}
 
 	errno = save_errno;
@@ -556,9 +597,10 @@ enum {
 	WGET_OPT_USER_AGENT = (1 << 6),
 	WGET_OPT_RETRIES    = (1 << 7),
 	WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 8),
-	WGET_OPT_PASSIVE    = (1 << 9),
-	WGET_OPT_HEADER     = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
-	WGET_OPT_POST_DATA  = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
+	WGET_OPT_DOT        = (1 << 9) * ENABLE_FEATURE_WGET_STATUSBAR,
+	WGET_OPT_PASSIVE    = (1 << 10),
+	WGET_OPT_HEADER     = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
+	WGET_OPT_POST_DATA  = (1 << 12) * ENABLE_FEATURE_WGET_LONG_OPTIONS,
 };
 
 static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
@@ -590,6 +632,8 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 			xwrite(output_fd, buf, n);
 #if ENABLE_FEATURE_WGET_STATUSBAR
 			transferred += n;
+			if (use_dot) 
+				progress_meter(1);
 #endif
 			if (G.got_clen)
 				content_len -= n;
@@ -599,7 +643,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd)
 			break;
 
 		safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */
- get_clen:
+get_clen:
 		safe_fgets(buf, sizeof(buf), dfp);
 		content_len = STRTOOFF(buf, NULL, 16);
 		/* FIXME: error check? */
@@ -653,6 +697,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
 		// "tries\0"            Required_argument "t"
 		// "timeout\0"          Required_argument "T"
 		/* Ignored (we always use PASV): */
+		"dot"                No_argument       "d"
 		"passive-ftp\0"      No_argument       "\xff"
 		"header\0"           Required_argument "\xfe"
 		"post-data\0"        Required_argument "\xfd"
@@ -666,7 +711,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
 #endif
 	/* server.allocated = target.allocated = NULL; */
 	opt_complementary = "-1" IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::");
-	opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:",
+	opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:d",
 				&fname_out, &dir_prefix,
 				&proxy_flag, &user_agent,
 				NULL, /* -t RETRIES */
@@ -734,6 +779,12 @@ int wget_main(int argc UNUSED_PARAM, char **argv)
 	}
 #if ENABLE_FEATURE_WGET_STATUSBAR
 	curfile = bb_get_last_path_component_nostrip(fname_out);
+
+	if (opt & WGET_OPT_DOT)
+		use_dot = 1;
+
+	if (!isatty(STDERR_FILENO)) 
+		use_dot = 1;
 #endif
 
 	/* Impossible?
-- 
1.6.2.5

