/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 */