PageRenderTime 72ms CodeModel.GetById 21ms app.highlight 44ms RepoModel.GetById 2ms app.codeStats 0ms

/ncftp-3.2.5/ncftp/progress.c

#
C | 501 lines | 394 code | 64 blank | 43 comment | 87 complexity | a428790d717a5a1348e45b1f9efefacf MD5 | raw file
Possible License(s): AGPL-3.0
  1/* progress.c
  2 *
  3 * Copyright (c) 1992-2005 by Mike Gleason.
  4 * All rights reserved.
  5 * 
  6 */
  7
  8#include "syshdrs.h"
  9#ifdef PRAGMA_HDRSTOP
 10#	pragma hdrstop
 11#endif
 12
 13#include "util.h"
 14#include "trace.h"
 15#include "progress.h"
 16#include "readln.h"
 17
 18#ifdef ncftp
 19#	include "log.h"
 20#	include "pref.h"
 21#endif	/* ncftp */
 22
 23extern const char *tcap_normal;
 24extern const char *tcap_reverse;
 25extern int gScreenColumns;
 26
 27#ifdef ncftp
 28extern char gRemoteCWD[];
 29#endif	/* ncftp */
 30
 31
 32double
 33FileSize(const double size, const char **uStr0, double *const uMult0)
 34{
 35	double uMult, uTotal;
 36	const char *uStr;
 37
 38	/* The comparisons below may look odd, but the reason
 39	 * for them is that we only want a maximum of 3 digits
 40	 * before the decimal point.  (I.e., we don't want to
 41	 * see "1017.2 kB", instead we want "0.99 MB".
 42	 */
 43	if (size > (999.5 * kGigabyte)) {
 44		uStr = "TB";
 45		uMult = kTerabyte;
 46	} else if (size > (999.5 * kMegabyte)) {
 47		uStr = "GB";
 48		uMult = kGigabyte;
 49	} else if (size > (999.5 * kKilobyte)) {
 50		uStr = "MB";
 51		uMult = kMegabyte;
 52	} else if (size > 999.5) {
 53		uStr = "kB";
 54		uMult = 1024;
 55	} else {
 56		uStr = "B";
 57		uMult = 1;
 58	}
 59	if (uStr0 != NULL)
 60		*uStr0 = uStr;
 61	if (uMult0 != NULL)
 62		*uMult0 = uMult;
 63	uTotal = size / ((double) uMult);
 64	if (uTotal < 0.0)
 65		uTotal = 0.0;
 66	return (uTotal);
 67}	/* FileSize */
 68
 69
 70
 71
 72void
 73PrSizeAndRateMeter(const FTPCIPtr cip, int mode)
 74{
 75	double rate = 0.0;
 76	const char *rStr;
 77	static const char *uStr;
 78	static double uMult;
 79	char localName[32];
 80	char line[128];
 81	int i;
 82
 83	switch (mode) {
 84		case kPrInitMsg:
 85			if (cip->expectedSize != kSizeUnknown) {
 86				cip->progress = PrStatBar;
 87				PrStatBar(cip, mode);
 88				return;
 89			}
 90			(void) FileSize((double) cip->expectedSize, &uStr, &uMult);
 91
 92			if (cip->lname == NULL) {
 93				localName[0] = '\0';
 94			} else {
 95				AbbrevStr(localName, cip->lname, sizeof(localName) - 2, 0);
 96				if ((cip->usingTAR) && (strlen(localName) < (sizeof(localName) - 6))) {
 97					STRNCAT(localName, " (TAR)");
 98				}
 99				(void) STRNCAT(localName, ":");
100			}
101			if (cip->useProgressMeter) {
102#ifdef ncftp
103				if (cip->usingTAR) {
104					if (OneTimeMessage("tar") != 0) {
105						(void) fprintf(stderr, "\n\
106Note: NcFTP is using on-the-fly TAR on the remote server, which retrieves the\n\
107entire directory as one operation.  This allows you to preserve exact file\n\
108timestamps, ownerships, and permissions, as well as a slight performance\n\
109boost.\n\
110\n\
111If you would rather retrieve each file individually, use the \"-T\" flag with\n\
112\"get\".  TAR mode cannot be resumed if the transfer fails, so if that happens\n\
113try \"get -T\" to resume the directory transfer.\n\n");
114					}
115				}
116#endif	/* ncftp */
117				(void) fprintf(stderr, "%-32s", localName);
118			}
119			break;
120
121		case kPrUpdateMsg:
122			rate = FileSize(cip->kBytesPerSec * 1024.0, &rStr, NULL);
123
124			if (cip->lname == NULL) {
125				localName[0] = '\0';
126			} else {
127				AbbrevStr(localName, cip->lname, sizeof(localName) - 2, 0);
128				if ((cip->usingTAR) && (strlen(localName) < (sizeof(localName) - 6))) {
129					STRNCAT(localName, " (TAR)");
130				}
131				(void) STRNCAT(localName, ":");
132			}
133
134#if defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_LLD)
135			(void) sprintf(line, "%-32s  %10lld bytes  %6.2f %s/s",
136				localName,
137				(longest_int) (cip->bytesTransferred + cip->startPoint),
138				rate,
139				rStr
140			);
141#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_QD)
142			(void) sprintf(line, "%-32s  %10qd bytes  %6.2f %s/s",
143				localName,
144				(longest_int) (cip->bytesTransferred + cip->startPoint),
145				rate,
146				rStr
147			);
148#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_I64D)
149			(void) sprintf(line, "%-32s  %10I64d bytes  %6.2f %s/s",
150				localName,
151				(longest_int) (cip->bytesTransferred + cip->startPoint),
152				rate,
153				rStr
154			);
155#else
156			(void) sprintf(line, "%-32s  %10ld bytes  %6.2f %s/s",
157				localName,
158				(long) (cip->bytesTransferred + cip->startPoint),
159				rate,
160				rStr
161			);
162#endif
163
164			/* Pad the rest of the line with spaces, to erase any
165			 * stuff that might have been left over from the last
166			 * update.
167			 */
168			for (i = (int) strlen(line); i < 80 - 2; i++)
169				line[i] = ' ';
170			line[i] = '\0';
171
172			/* Print the updated information. */
173			(void) fprintf(stderr, "\r%s", line);
174
175#if defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_LLD)
176			SetXtermTitle("%s - [%lld bytes]", cip->lname, (longest_int) (cip->bytesTransferred + cip->startPoint));
177#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_QD)
178			SetXtermTitle("%s - [%qd bytes]", cip->lname, (longest_int) (cip->bytesTransferred + cip->startPoint));
179#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_I64D)
180			SetXtermTitle("%s - [%I64d bytes]", cip->lname, (longest_int) (cip->bytesTransferred + cip->startPoint));
181#else
182			SetXtermTitle("%s - [%ld bytes]", cip->lname, (long) (cip->bytesTransferred + cip->startPoint));
183#endif
184			break;
185
186		case kPrEndMsg:
187			(void) fprintf(stderr, "\n\r");
188#ifdef ncftp
189			if (cip->rname != NULL) {
190				char url[256];
191
192				FileToURL(url, sizeof(url), cip->rname, gRemoteCWD, cip->startingWorkingDirectory, cip->user, cip->pass, cip->host, cip->port);
193				LogXfer((cip->netMode == kNetReading) ? "get" : "put", url);
194			}	
195#endif
196			break;
197	}
198}	/* PrSizeAndRateMeter */
199
200
201
202
203void
204PrStatBar(const FTPCIPtr cip, int mode)
205{
206	double rate, done;
207	int secLeft, minLeft;
208	const char *rStr;
209	static const char *uStr;
210	static double uTotal, uMult;
211	const char *stall;
212	char localName[80];
213	char line[128];
214	int i;
215
216	switch (mode) {
217		case kPrInitMsg:
218			fflush(stdout);
219			if (cip->expectedSize == kSizeUnknown) {
220				cip->progress = PrSizeAndRateMeter;
221				PrSizeAndRateMeter(cip, mode);
222				return;
223			}
224			uTotal = FileSize((double) cip->expectedSize, &uStr, &uMult);
225
226			if (cip->lname == NULL) {
227				localName[0] = '\0';
228			} else {
229				/* Leave room for a ':' and '\0'. */
230				AbbrevStr(localName, cip->lname, sizeof(localName) - 2, 0);
231				(void) STRNCAT(localName, ":");
232			}
233
234			if (cip->useProgressMeter)
235				(void) fprintf(stderr, "%-32s", localName);
236			break;
237
238		case kPrUpdateMsg:
239			secLeft = (int) (cip->secLeft + 0.5);
240			minLeft = secLeft / 60;
241			secLeft = secLeft - (minLeft * 60);
242			if (minLeft > 999) {
243				minLeft = 999;
244				secLeft = 59;
245			}
246
247			rate = FileSize(cip->kBytesPerSec * 1024.0, &rStr, NULL);
248			done = (double) (cip->bytesTransferred + cip->startPoint) / uMult;
249
250			if (cip->lname == NULL) {
251				localName[0] = '\0';
252			} else {
253				AbbrevStr(localName, cip->lname, 31, 0);
254				(void) STRNCAT(localName, ":");
255			}
256
257			if (cip->canceling > 0)
258				stall = "X";
259			else if (cip->stalled < 2)
260				stall = " ";
261			else if (cip->stalled < 15)
262				stall = "-";
263			else
264				stall = "=";
265
266			(void) sprintf(line, "%-32s  ETA: %3d:%02d  %6.2f/%6.2f %.2s  %6.2f %.2s/s %s ",
267				localName,
268				minLeft,
269				secLeft,
270				done,
271				uTotal,
272				uStr,
273				rate,
274				rStr,
275				stall
276			);
277
278			/* Print the updated information. */
279			(void) fprintf(stderr, "\r%s", line);
280
281			SetXtermTitle("%s - [%.1f%%]", cip->lname, cip->percentCompleted);
282			break;
283
284		case kPrEndMsg:
285
286			rate = FileSize(cip->kBytesPerSec * 1024.0, &rStr, NULL);
287			done = (double) (cip->bytesTransferred + cip->startPoint) / uMult;
288
289			if (cip->expectedSize == (cip->bytesTransferred + cip->startPoint)) {
290				if (cip->lname == NULL) {
291					localName[0] = '\0';
292				} else {
293					AbbrevStr(localName, cip->lname, 52, 0);
294					(void) STRNCAT(localName, ":");
295				}
296
297				(void) sprintf(line, "%-53s  %6.2f %.2s  %6.2f %.2s/s  ",
298					localName,
299					uTotal,
300					uStr,
301					rate,
302					rStr
303				);
304			} else {
305				if (cip->lname == NULL) {
306					localName[0] = '\0';
307				} else {
308					AbbrevStr(localName, cip->lname, 45, 0);
309					(void) STRNCAT(localName, ":");
310				}
311
312				(void) sprintf(line, "%-46s  %6.2f/%6.2f %.2s  %6.2f %.2s/s  ",
313					localName,
314					done,
315					uTotal,
316					uStr,
317					rate,
318					rStr
319				);
320			}
321
322			/* Pad the rest of the line with spaces, to erase any
323			 * stuff that might have been left over from the last
324			 * update.
325			 */
326			for (i = (int) strlen(line); i < 80 - 2; i++)
327				line[i] = ' ';
328			line[i] = '\0';
329
330			/* Print the updated information. */
331			(void) fprintf(stderr, "\r%s\n\r", line);
332#ifdef ncftp
333			if (cip->rname != NULL) {
334				char url[256];
335
336				FileToURL(url, sizeof(url), cip->rname, gRemoteCWD, cip->startingWorkingDirectory, cip->user, cip->pass, cip->host, cip->port);
337				LogXfer((cip->netMode == kNetReading) ? "get" : "put", url);
338			}	
339#endif
340			break;
341	}
342}	/* PrStatBar */
343
344
345
346
347/* This one is the brainchild of my comrade, Phil Dietz.  It shows the
348 * progress as a fancy bar graph.
349 */
350void
351PrPhilBar(const FTPCIPtr cip, int mode)
352{
353	int perc;
354	longest_int s;
355	int curBarLen;
356	static int maxBarLen;
357	char spec1[64], spec3[64];
358	static char bar[256];
359	int i;
360	int secsLeft, minLeft;
361	static const char *uStr;
362	static double uMult;
363	double rate;
364	const char *rStr;
365
366	switch (mode) {
367		case kPrInitMsg:
368			if (cip->expectedSize == kSizeUnknown) {
369				cip->progress = PrSizeAndRateMeter;
370				PrSizeAndRateMeter(cip, mode);
371				return;
372			}
373			(void) FileSize((double) cip->expectedSize, &uStr, &uMult);
374			fflush(stdout);
375			fprintf(stderr, "%s file: %s \n",
376				(cip->netMode == kNetReading) ? "Receiving" : "Sending",
377				cip->lname
378			);
379			
380			for (i=0; i < (int) sizeof(bar) - 1; i++)
381				bar[i] = '=';
382			bar[i] = '\0';
383
384			/* Compute the size of the bar itself.  This sits between
385			 * two numbers, one on each side of the screen.  So the
386			 * bar length will vary, depending on how many digits we
387			 * need to display the size of the file.
388			 */
389			maxBarLen = gScreenColumns - 1 - 28;
390			for (s = cip->expectedSize; s > 0; s /= 10L)
391				maxBarLen--;
392			
393			/* Create a specification we can hand to printf. */
394#if defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_LLD)
395			(void) sprintf(spec1, "      0 %%%ds %%lld bytes. ETA: --:--", maxBarLen);
396				
397			/* Print the first invocation, which is an empty graph
398			 * plus the other stuff.
399			 */
400			fprintf(stderr, spec1, " ", cip->expectedSize);
401#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_QD)
402			(void) sprintf(spec1, "      0 %%%ds %%qd bytes. ETA: --:--", maxBarLen);
403			fprintf(stderr, spec1, " ", cip->expectedSize);
404#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_I64D)
405			(void) sprintf(spec1, "      0 %%%ds %%I64d bytes. ETA: --:--", maxBarLen);
406			fprintf(stderr, spec1, " ", cip->expectedSize);
407#else
408			(void) sprintf(spec1, "      0 %%%ds %%ld bytes. ETA: --:--", maxBarLen);
409			fprintf(stderr, spec1, " ", (long) cip->expectedSize);
410#endif
411			fflush(stdout);
412			break;
413
414		case kPrUpdateMsg:
415			/* Compute how much of the bar should be colored in. */
416			curBarLen = (int) (cip->percentCompleted * 0.01 * (double)maxBarLen);
417
418			/* Colored portion must be at least one character so
419			 * the spec isn't '%0s' which would screw the right side
420			 * of the indicator.
421			 */
422			if (curBarLen < 1)
423				curBarLen = 1;
424			
425			bar[curBarLen - 1] = '>';
426			bar[curBarLen] = '\0';
427
428			/* Make the spec, so we can print the bar and the other stuff. */
429			STRNCPY(spec1, "\r%3d%%  0 ");
430
431#if defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_LLD)
432			(void) sprintf(spec3, "%%%ds %%lld bytes. %s%%3d:%%02d", 
433				maxBarLen - curBarLen,
434				"ETA:"
435			);
436#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_QD)
437			(void) sprintf(spec3, "%%%ds %%qd bytes. %s%%3d:%%02d", 
438				maxBarLen - curBarLen,
439				"ETA:"
440			);
441#elif defined(HAVE_LONG_LONG) && defined(PRINTF_LONG_LONG_I64D)
442			(void) sprintf(spec3, "%%%ds %%I64d bytes. %s%%3d:%%02d", 
443				maxBarLen - curBarLen,
444				"ETA:"
445			);
446#else
447			(void) sprintf(spec3, "%%%ds %%ld bytes. %s%%3d:%%02d", 
448				maxBarLen - curBarLen,
449				"ETA:"
450			);
451#endif
452			
453			/* We also show the percentage as a number at the left side. */
454			perc = (int) (cip->percentCompleted);
455			secsLeft = (int) (cip->secLeft);
456			minLeft = secsLeft / 60;
457			secsLeft = secsLeft - (minLeft * 60);
458			if (minLeft > 999) {
459				minLeft = 999;
460				secsLeft = 59;
461			}
462			
463			/* Print the updated information. */
464			fprintf(stderr, spec1, perc);
465			fprintf(stderr, "%s%s%s", tcap_reverse, bar, tcap_normal);
466			fprintf(stderr, spec3,
467				"",
468				cip->expectedSize,
469				minLeft,
470				secsLeft
471			);
472
473			bar[curBarLen - 1] = '=';
474			bar[curBarLen] = '=';
475			fflush(stdout);
476
477			SetXtermTitle("%s - [%.1f%%]", cip->lname, cip->percentCompleted);
478			break;
479		case kPrEndMsg:
480			printf("\n");
481			rate = FileSize(cip->kBytesPerSec * 1024.0, &rStr, NULL);
482
483			(void) fprintf(stderr, "%s: finished in %ld:%02ld:%02ld, %.2f %s/s\n",
484				(cip->lname == NULL) ? "remote" : cip->lname,
485				(long) cip->sec / 3600L,
486				((long) cip->sec / 60L) % 60L,
487				((long) cip->sec % 60L),
488				rate,
489				rStr
490			);
491#ifdef ncftp
492			if (cip->rname != NULL) {
493				char url[256];
494
495				FileToURL(url, sizeof(url), cip->rname, gRemoteCWD, cip->startingWorkingDirectory, cip->user, cip->pass, cip->host, cip->port);
496				LogXfer((cip->netMode == kNetReading) ? "get" : "put", url);
497			}	
498#endif
499			break;
500	}
501}	/* PrPhilBar */