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