Annotation of embedaddon/curl/src/tool_progress.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
! 9: *
! 10: * This software is licensed as described in the file COPYING, which
! 11: * you should have received as part of this distribution. The terms
! 12: * are also available at https://curl.haxx.se/docs/copyright.html.
! 13: *
! 14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
! 15: * copies of the Software, and permit persons to whom the Software is
! 16: * furnished to do so, under the terms of the COPYING file.
! 17: *
! 18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
! 19: * KIND, either express or implied.
! 20: *
! 21: ***************************************************************************/
! 22: #include "tool_setup.h"
! 23: #include "tool_operate.h"
! 24: #include "tool_progress.h"
! 25: #include "tool_util.h"
! 26:
! 27: #define ENABLE_CURLX_PRINTF
! 28: /* use our own printf() functions */
! 29: #include "curlx.h"
! 30:
! 31: /* The point of this function would be to return a string of the input data,
! 32: but never longer than 5 columns (+ one zero byte).
! 33: Add suffix k, M, G when suitable... */
! 34: static char *max5data(curl_off_t bytes, char *max5)
! 35: {
! 36: #define ONE_KILOBYTE CURL_OFF_T_C(1024)
! 37: #define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE)
! 38: #define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE)
! 39: #define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE)
! 40: #define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
! 41:
! 42: if(bytes < CURL_OFF_T_C(100000))
! 43: msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
! 44:
! 45: else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
! 46: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
! 47:
! 48: else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
! 49: /* 'XX.XM' is good as long as we're less than 100 megs */
! 50: msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
! 51: CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
! 52: (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
! 53:
! 54: #if (CURL_SIZEOF_CURL_OFF_T > 4)
! 55:
! 56: else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
! 57: /* 'XXXXM' is good until we're at 10000MB or above */
! 58: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
! 59:
! 60: else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
! 61: /* 10000 MB - 100 GB, we show it as XX.XG */
! 62: msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
! 63: CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
! 64: (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
! 65:
! 66: else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
! 67: /* up to 10000GB, display without decimal: XXXXG */
! 68: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);
! 69:
! 70: else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
! 71: /* up to 10000TB, display without decimal: XXXXT */
! 72: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);
! 73:
! 74: else
! 75: /* up to 10000PB, display without decimal: XXXXP */
! 76: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
! 77:
! 78: /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
! 79: can hold, but our data type is signed so 8192PB will be the maximum. */
! 80:
! 81: #else
! 82:
! 83: else
! 84: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
! 85:
! 86: #endif
! 87:
! 88: return max5;
! 89: }
! 90:
! 91: int xferinfo_cb(void *clientp,
! 92: curl_off_t dltotal,
! 93: curl_off_t dlnow,
! 94: curl_off_t ultotal,
! 95: curl_off_t ulnow)
! 96: {
! 97: struct per_transfer *per = clientp;
! 98: struct OperationConfig *config = per->config;
! 99: per->dltotal = dltotal;
! 100: per->dlnow = dlnow;
! 101: per->ultotal = ultotal;
! 102: per->ulnow = ulnow;
! 103:
! 104: if(config->readbusy) {
! 105: config->readbusy = FALSE;
! 106: curl_easy_pause(per->curl, CURLPAUSE_CONT);
! 107: }
! 108:
! 109: return 0;
! 110: }
! 111:
! 112: /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
! 113: byte) */
! 114: static void time2str(char *r, curl_off_t seconds)
! 115: {
! 116: curl_off_t h;
! 117: if(seconds <= 0) {
! 118: strcpy(r, "--:--:--");
! 119: return;
! 120: }
! 121: h = seconds / CURL_OFF_T_C(3600);
! 122: if(h <= CURL_OFF_T_C(99)) {
! 123: curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
! 124: curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
! 125: msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T
! 126: ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
! 127: }
! 128: else {
! 129: /* this equals to more than 99 hours, switch to a more suitable output
! 130: format to fit within the limits. */
! 131: curl_off_t d = seconds / CURL_OFF_T_C(86400);
! 132: h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
! 133: if(d <= CURL_OFF_T_C(999))
! 134: msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
! 135: "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
! 136: else
! 137: msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
! 138: }
! 139: }
! 140:
! 141: static curl_off_t all_dltotal = 0;
! 142: static curl_off_t all_ultotal = 0;
! 143: static curl_off_t all_dlalready = 0;
! 144: static curl_off_t all_ulalready = 0;
! 145:
! 146: curl_off_t all_xfers = 0; /* current total */
! 147:
! 148: struct speedcount {
! 149: curl_off_t dl;
! 150: curl_off_t ul;
! 151: struct timeval stamp;
! 152: };
! 153: #define SPEEDCNT 10
! 154: static unsigned int speedindex;
! 155: static bool indexwrapped;
! 156: static struct speedcount speedstore[SPEEDCNT];
! 157:
! 158: /*
! 159: |DL% UL% Dled Uled Xfers Live Qd Total Current Left Speed
! 160: | 6 -- 9.9G 0 2 2 0 0:00:40 0:00:02 0:00:37 4087M
! 161: */
! 162: bool progress_meter(struct GlobalConfig *global,
! 163: struct timeval *start,
! 164: bool final)
! 165: {
! 166: static struct timeval stamp;
! 167: static bool header = FALSE;
! 168: struct timeval now;
! 169: long diff;
! 170:
! 171: if(global->noprogress)
! 172: return FALSE;
! 173:
! 174: now = tvnow();
! 175: diff = tvdiff(now, stamp);
! 176:
! 177: if(!header) {
! 178: header = TRUE;
! 179: fputs("DL% UL% Dled Uled Xfers Live Qd "
! 180: "Total Current Left Speed\n",
! 181: global->errors);
! 182: }
! 183: if(final || (diff > 500)) {
! 184: char time_left[10];
! 185: char time_total[10];
! 186: char time_spent[10];
! 187: char buffer[3][6];
! 188: curl_off_t spent = tvdiff(now, *start)/1000;
! 189: char dlpercen[4]="--";
! 190: char ulpercen[4]="--";
! 191: struct per_transfer *per;
! 192: curl_off_t all_dlnow = 0;
! 193: curl_off_t all_ulnow = 0;
! 194: bool dlknown = TRUE;
! 195: bool ulknown = TRUE;
! 196: curl_off_t all_running = 0; /* in progress */
! 197: curl_off_t all_queued = 0; /* pending */
! 198: curl_off_t speed = 0;
! 199: unsigned int i;
! 200: stamp = now;
! 201:
! 202: /* first add the amounts of the already completed transfers */
! 203: all_dlnow += all_dlalready;
! 204: all_ulnow += all_ulalready;
! 205:
! 206: for(per = transfers; per; per = per->next) {
! 207: all_dlnow += per->dlnow;
! 208: all_ulnow += per->ulnow;
! 209: if(!per->dltotal)
! 210: dlknown = FALSE;
! 211: else if(!per->dltotal_added) {
! 212: /* only add this amount once */
! 213: all_dltotal += per->dltotal;
! 214: per->dltotal_added = TRUE;
! 215: }
! 216: if(!per->ultotal)
! 217: ulknown = FALSE;
! 218: else if(!per->ultotal_added) {
! 219: /* only add this amount once */
! 220: all_ultotal += per->ultotal;
! 221: per->ultotal_added = TRUE;
! 222: }
! 223: if(!per->added)
! 224: all_queued++;
! 225: else
! 226: all_running++;
! 227: }
! 228: if(dlknown && all_dltotal)
! 229: /* TODO: handle integer overflow */
! 230: msnprintf(dlpercen, sizeof(dlpercen), "%3d",
! 231: all_dlnow * 100 / all_dltotal);
! 232: if(ulknown && all_ultotal)
! 233: /* TODO: handle integer overflow */
! 234: msnprintf(ulpercen, sizeof(ulpercen), "%3d",
! 235: all_ulnow * 100 / all_ultotal);
! 236:
! 237: /* get the transfer speed, the higher of the two */
! 238:
! 239: i = speedindex;
! 240: speedstore[i].dl = all_dlnow;
! 241: speedstore[i].ul = all_ulnow;
! 242: speedstore[i].stamp = now;
! 243: if(++speedindex >= SPEEDCNT) {
! 244: indexwrapped = TRUE;
! 245: speedindex = 0;
! 246: }
! 247:
! 248: {
! 249: long deltams;
! 250: curl_off_t dl;
! 251: curl_off_t ul;
! 252: curl_off_t dls;
! 253: curl_off_t uls;
! 254: if(indexwrapped) {
! 255: /* 'speedindex' is the oldest stored data */
! 256: deltams = tvdiff(now, speedstore[speedindex].stamp);
! 257: dl = all_dlnow - speedstore[speedindex].dl;
! 258: ul = all_ulnow - speedstore[speedindex].ul;
! 259: }
! 260: else {
! 261: /* since the beginning */
! 262: deltams = tvdiff(now, *start);
! 263: dl = all_dlnow;
! 264: ul = all_ulnow;
! 265: }
! 266: dls = (curl_off_t)((double)dl / ((double)deltams/1000.0));
! 267: uls = (curl_off_t)((double)ul / ((double)deltams/1000.0));
! 268: speed = dls > uls ? dls : uls;
! 269: }
! 270:
! 271:
! 272: if(dlknown && speed) {
! 273: curl_off_t est = all_dltotal / speed;
! 274: curl_off_t left = (all_dltotal - all_dlnow) / speed;
! 275: time2str(time_left, left);
! 276: time2str(time_total, est);
! 277: }
! 278: else {
! 279: time2str(time_left, 0);
! 280: time2str(time_total, 0);
! 281: }
! 282: time2str(time_spent, spent);
! 283:
! 284: fprintf(global->errors,
! 285: "\r"
! 286: "%-3s " /* percent downloaded */
! 287: "%-3s " /* percent uploaded */
! 288: "%s " /* Dled */
! 289: "%s " /* Uled */
! 290: "%5" CURL_FORMAT_CURL_OFF_T " " /* Xfers */
! 291: "%5" CURL_FORMAT_CURL_OFF_T " " /* Live */
! 292: "%5" CURL_FORMAT_CURL_OFF_T " " /* Queued */
! 293: "%s " /* Total time */
! 294: "%s " /* Current time */
! 295: "%s " /* Time left */
! 296: "%s " /* Speed */
! 297: "%5s" /* final newline */,
! 298:
! 299: dlpercen, /* 3 letters */
! 300: ulpercen, /* 3 letters */
! 301: max5data(all_dlnow, buffer[0]),
! 302: max5data(all_ulnow, buffer[1]),
! 303: all_xfers,
! 304: all_running,
! 305: all_queued,
! 306: time_total,
! 307: time_spent,
! 308: time_left,
! 309: max5data(speed, buffer[2]), /* speed */
! 310: final ? "\n" :"");
! 311: return TRUE;
! 312: }
! 313: return FALSE;
! 314: }
! 315:
! 316: void progress_finalize(struct per_transfer *per)
! 317: {
! 318: /* get the numbers before this transfer goes away */
! 319: all_dlalready += per->dlnow;
! 320: all_ulalready += per->ulnow;
! 321: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>