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