Annotation of embedaddon/curl/lib/progress.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2019, 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:
! 23: #include "curl_setup.h"
! 24:
! 25: #include "urldata.h"
! 26: #include "sendf.h"
! 27: #include "multiif.h"
! 28: #include "progress.h"
! 29: #include "timeval.h"
! 30: #include "curl_printf.h"
! 31:
! 32: /* check rate limits within this many recent milliseconds, at minimum. */
! 33: #define MIN_RATE_LIMIT_PERIOD 3000
! 34:
! 35: #ifndef CURL_DISABLE_PROGRESS_METER
! 36: /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
! 37: byte) */
! 38: static void time2str(char *r, curl_off_t seconds)
! 39: {
! 40: curl_off_t h;
! 41: if(seconds <= 0) {
! 42: strcpy(r, "--:--:--");
! 43: return;
! 44: }
! 45: h = seconds / CURL_OFF_T_C(3600);
! 46: if(h <= CURL_OFF_T_C(99)) {
! 47: curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
! 48: curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
! 49: msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T
! 50: ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
! 51: }
! 52: else {
! 53: /* this equals to more than 99 hours, switch to a more suitable output
! 54: format to fit within the limits. */
! 55: curl_off_t d = seconds / CURL_OFF_T_C(86400);
! 56: h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
! 57: if(d <= CURL_OFF_T_C(999))
! 58: msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
! 59: "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
! 60: else
! 61: msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
! 62: }
! 63: }
! 64:
! 65: /* The point of this function would be to return a string of the input data,
! 66: but never longer than 5 columns (+ one zero byte).
! 67: Add suffix k, M, G when suitable... */
! 68: static char *max5data(curl_off_t bytes, char *max5)
! 69: {
! 70: #define ONE_KILOBYTE CURL_OFF_T_C(1024)
! 71: #define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE)
! 72: #define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE)
! 73: #define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE)
! 74: #define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
! 75:
! 76: if(bytes < CURL_OFF_T_C(100000))
! 77: msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
! 78:
! 79: else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
! 80: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
! 81:
! 82: else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
! 83: /* 'XX.XM' is good as long as we're less than 100 megs */
! 84: msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
! 85: CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
! 86: (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
! 87:
! 88: #if (CURL_SIZEOF_CURL_OFF_T > 4)
! 89:
! 90: else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
! 91: /* 'XXXXM' is good until we're at 10000MB or above */
! 92: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
! 93:
! 94: else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
! 95: /* 10000 MB - 100 GB, we show it as XX.XG */
! 96: msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
! 97: CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
! 98: (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
! 99:
! 100: else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
! 101: /* up to 10000GB, display without decimal: XXXXG */
! 102: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);
! 103:
! 104: else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
! 105: /* up to 10000TB, display without decimal: XXXXT */
! 106: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);
! 107:
! 108: else
! 109: /* up to 10000PB, display without decimal: XXXXP */
! 110: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
! 111:
! 112: /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
! 113: can hold, but our data type is signed so 8192PB will be the maximum. */
! 114:
! 115: #else
! 116:
! 117: else
! 118: msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
! 119:
! 120: #endif
! 121:
! 122: return max5;
! 123: }
! 124: #endif
! 125:
! 126: /*
! 127:
! 128: New proposed interface, 9th of February 2000:
! 129:
! 130: pgrsStartNow() - sets start time
! 131: pgrsSetDownloadSize(x) - known expected download size
! 132: pgrsSetUploadSize(x) - known expected upload size
! 133: pgrsSetDownloadCounter() - amount of data currently downloaded
! 134: pgrsSetUploadCounter() - amount of data currently uploaded
! 135: pgrsUpdate() - show progress
! 136: pgrsDone() - transfer complete
! 137:
! 138: */
! 139:
! 140: int Curl_pgrsDone(struct connectdata *conn)
! 141: {
! 142: int rc;
! 143: struct Curl_easy *data = conn->data;
! 144: data->progress.lastshow = 0;
! 145: rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
! 146: if(rc)
! 147: return rc;
! 148:
! 149: if(!(data->progress.flags & PGRS_HIDE) &&
! 150: !data->progress.callback)
! 151: /* only output if we don't use a progress callback and we're not
! 152: * hidden */
! 153: fprintf(data->set.err, "\n");
! 154:
! 155: data->progress.speeder_c = 0; /* reset the progress meter display */
! 156: return 0;
! 157: }
! 158:
! 159: /* reset the known transfer sizes */
! 160: void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
! 161: {
! 162: Curl_pgrsSetDownloadSize(data, -1);
! 163: Curl_pgrsSetUploadSize(data, -1);
! 164: }
! 165:
! 166: /*
! 167: * @unittest: 1399
! 168: */
! 169: void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
! 170: {
! 171: struct curltime now = Curl_now();
! 172: timediff_t *delta = NULL;
! 173:
! 174: switch(timer) {
! 175: default:
! 176: case TIMER_NONE:
! 177: /* mistake filter */
! 178: break;
! 179: case TIMER_STARTOP:
! 180: /* This is set at the start of a transfer */
! 181: data->progress.t_startop = now;
! 182: break;
! 183: case TIMER_STARTSINGLE:
! 184: /* This is set at the start of each single fetch */
! 185: data->progress.t_startsingle = now;
! 186: data->progress.is_t_startransfer_set = false;
! 187: break;
! 188: case TIMER_STARTACCEPT:
! 189: data->progress.t_acceptdata = now;
! 190: break;
! 191: case TIMER_NAMELOOKUP:
! 192: delta = &data->progress.t_nslookup;
! 193: break;
! 194: case TIMER_CONNECT:
! 195: delta = &data->progress.t_connect;
! 196: break;
! 197: case TIMER_APPCONNECT:
! 198: delta = &data->progress.t_appconnect;
! 199: break;
! 200: case TIMER_PRETRANSFER:
! 201: delta = &data->progress.t_pretransfer;
! 202: break;
! 203: case TIMER_STARTTRANSFER:
! 204: delta = &data->progress.t_starttransfer;
! 205: /* prevent updating t_starttransfer unless:
! 206: * 1) this is the first time we're setting t_starttransfer
! 207: * 2) a redirect has occurred since the last time t_starttransfer was set
! 208: * This prevents repeated invocations of the function from incorrectly
! 209: * changing the t_starttransfer time.
! 210: */
! 211: if(data->progress.is_t_startransfer_set) {
! 212: return;
! 213: }
! 214: else {
! 215: data->progress.is_t_startransfer_set = true;
! 216: break;
! 217: }
! 218: case TIMER_POSTRANSFER:
! 219: /* this is the normal end-of-transfer thing */
! 220: break;
! 221: case TIMER_REDIRECT:
! 222: data->progress.t_redirect = Curl_timediff_us(now, data->progress.start);
! 223: break;
! 224: }
! 225: if(delta) {
! 226: timediff_t us = Curl_timediff_us(now, data->progress.t_startsingle);
! 227: if(us < 1)
! 228: us = 1; /* make sure at least one microsecond passed */
! 229: *delta += us;
! 230: }
! 231: }
! 232:
! 233: void Curl_pgrsStartNow(struct Curl_easy *data)
! 234: {
! 235: data->progress.speeder_c = 0; /* reset the progress meter display */
! 236: data->progress.start = Curl_now();
! 237: data->progress.is_t_startransfer_set = false;
! 238: data->progress.ul_limit_start.tv_sec = 0;
! 239: data->progress.ul_limit_start.tv_usec = 0;
! 240: data->progress.dl_limit_start.tv_sec = 0;
! 241: data->progress.dl_limit_start.tv_usec = 0;
! 242: data->progress.downloaded = 0;
! 243: data->progress.uploaded = 0;
! 244: /* clear all bits except HIDE and HEADERS_OUT */
! 245: data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
! 246: Curl_ratelimit(data, data->progress.start);
! 247: }
! 248:
! 249: /*
! 250: * This is used to handle speed limits, calculating how many milliseconds to
! 251: * wait until we're back under the speed limit, if needed.
! 252: *
! 253: * The way it works is by having a "starting point" (time & amount of data
! 254: * transferred by then) used in the speed computation, to be used instead of
! 255: * the start of the transfer. This starting point is regularly moved as
! 256: * transfer goes on, to keep getting accurate values (instead of average over
! 257: * the entire transfer).
! 258: *
! 259: * This function takes the current amount of data transferred, the amount at
! 260: * the starting point, the limit (in bytes/s), the time of the starting point
! 261: * and the current time.
! 262: *
! 263: * Returns 0 if no waiting is needed or when no waiting is needed but the
! 264: * starting point should be reset (to current); or the number of milliseconds
! 265: * to wait to get back under the speed limit.
! 266: */
! 267: timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
! 268: curl_off_t startsize,
! 269: curl_off_t limit,
! 270: struct curltime start,
! 271: struct curltime now)
! 272: {
! 273: curl_off_t size = cursize - startsize;
! 274: timediff_t minimum;
! 275: timediff_t actual;
! 276:
! 277: if(!limit || !size)
! 278: return 0;
! 279:
! 280: /*
! 281: * 'minimum' is the number of milliseconds 'size' should take to download to
! 282: * stay below 'limit'.
! 283: */
! 284: if(size < CURL_OFF_T_MAX/1000)
! 285: minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit);
! 286: else {
! 287: minimum = (time_t) (size / limit);
! 288: if(minimum < TIMEDIFF_T_MAX/1000)
! 289: minimum *= 1000;
! 290: else
! 291: minimum = TIMEDIFF_T_MAX;
! 292: }
! 293:
! 294: /*
! 295: * 'actual' is the time in milliseconds it took to actually download the
! 296: * last 'size' bytes.
! 297: */
! 298: actual = Curl_timediff(now, start);
! 299: if(actual < minimum) {
! 300: /* if it downloaded the data faster than the limit, make it wait the
! 301: difference */
! 302: return (minimum - actual);
! 303: }
! 304:
! 305: return 0;
! 306: }
! 307:
! 308: /*
! 309: * Set the number of downloaded bytes so far.
! 310: */
! 311: void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
! 312: {
! 313: data->progress.downloaded = size;
! 314: }
! 315:
! 316: /*
! 317: * Update the timestamp and sizestamp to use for rate limit calculations.
! 318: */
! 319: void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
! 320: {
! 321: /* don't set a new stamp unless the time since last update is long enough */
! 322: if(data->set.max_recv_speed > 0) {
! 323: if(Curl_timediff(now, data->progress.dl_limit_start) >=
! 324: MIN_RATE_LIMIT_PERIOD) {
! 325: data->progress.dl_limit_start = now;
! 326: data->progress.dl_limit_size = data->progress.downloaded;
! 327: }
! 328: }
! 329: if(data->set.max_send_speed > 0) {
! 330: if(Curl_timediff(now, data->progress.ul_limit_start) >=
! 331: MIN_RATE_LIMIT_PERIOD) {
! 332: data->progress.ul_limit_start = now;
! 333: data->progress.ul_limit_size = data->progress.uploaded;
! 334: }
! 335: }
! 336: }
! 337:
! 338: /*
! 339: * Set the number of uploaded bytes so far.
! 340: */
! 341: void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
! 342: {
! 343: data->progress.uploaded = size;
! 344: }
! 345:
! 346: void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
! 347: {
! 348: if(size >= 0) {
! 349: data->progress.size_dl = size;
! 350: data->progress.flags |= PGRS_DL_SIZE_KNOWN;
! 351: }
! 352: else {
! 353: data->progress.size_dl = 0;
! 354: data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
! 355: }
! 356: }
! 357:
! 358: void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
! 359: {
! 360: if(size >= 0) {
! 361: data->progress.size_ul = size;
! 362: data->progress.flags |= PGRS_UL_SIZE_KNOWN;
! 363: }
! 364: else {
! 365: data->progress.size_ul = 0;
! 366: data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
! 367: }
! 368: }
! 369:
! 370: /* returns TRUE if it's time to show the progress meter */
! 371: static bool progress_calc(struct connectdata *conn, struct curltime now)
! 372: {
! 373: curl_off_t timespent;
! 374: curl_off_t timespent_ms; /* milliseconds */
! 375: struct Curl_easy *data = conn->data;
! 376: curl_off_t dl = data->progress.downloaded;
! 377: curl_off_t ul = data->progress.uploaded;
! 378: bool timetoshow = FALSE;
! 379:
! 380: /* The time spent so far (from the start) */
! 381: data->progress.timespent = Curl_timediff_us(now, data->progress.start);
! 382: timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */
! 383: timespent_ms = (curl_off_t)data->progress.timespent/1000; /* ms */
! 384:
! 385: /* The average download speed this far */
! 386: if(dl < CURL_OFF_T_MAX/1000)
! 387: data->progress.dlspeed = (dl * 1000 / (timespent_ms>0?timespent_ms:1));
! 388: else
! 389: data->progress.dlspeed = (dl / (timespent>0?timespent:1));
! 390:
! 391: /* The average upload speed this far */
! 392: if(ul < CURL_OFF_T_MAX/1000)
! 393: data->progress.ulspeed = (ul * 1000 / (timespent_ms>0?timespent_ms:1));
! 394: else
! 395: data->progress.ulspeed = (ul / (timespent>0?timespent:1));
! 396:
! 397: /* Calculations done at most once a second, unless end is reached */
! 398: if(data->progress.lastshow != now.tv_sec) {
! 399: int countindex; /* amount of seconds stored in the speeder array */
! 400: int nowindex = data->progress.speeder_c% CURR_TIME;
! 401: data->progress.lastshow = now.tv_sec;
! 402: timetoshow = TRUE;
! 403:
! 404: /* Let's do the "current speed" thing, with the dl + ul speeds
! 405: combined. Store the speed at entry 'nowindex'. */
! 406: data->progress.speeder[ nowindex ] =
! 407: data->progress.downloaded + data->progress.uploaded;
! 408:
! 409: /* remember the exact time for this moment */
! 410: data->progress.speeder_time [ nowindex ] = now;
! 411:
! 412: /* advance our speeder_c counter, which is increased every time we get
! 413: here and we expect it to never wrap as 2^32 is a lot of seconds! */
! 414: data->progress.speeder_c++;
! 415:
! 416: /* figure out how many index entries of data we have stored in our speeder
! 417: array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
! 418: transfer. Imagine, after one second we have filled in two entries,
! 419: after two seconds we've filled in three entries etc. */
! 420: countindex = ((data->progress.speeder_c >= CURR_TIME)?
! 421: CURR_TIME:data->progress.speeder_c) - 1;
! 422:
! 423: /* first of all, we don't do this if there's no counted seconds yet */
! 424: if(countindex) {
! 425: int checkindex;
! 426: timediff_t span_ms;
! 427:
! 428: /* Get the index position to compare with the 'nowindex' position.
! 429: Get the oldest entry possible. While we have less than CURR_TIME
! 430: entries, the first entry will remain the oldest. */
! 431: checkindex = (data->progress.speeder_c >= CURR_TIME)?
! 432: data->progress.speeder_c%CURR_TIME:0;
! 433:
! 434: /* Figure out the exact time for the time span */
! 435: span_ms = Curl_timediff(now, data->progress.speeder_time[checkindex]);
! 436: if(0 == span_ms)
! 437: span_ms = 1; /* at least one millisecond MUST have passed */
! 438:
! 439: /* Calculate the average speed the last 'span_ms' milliseconds */
! 440: {
! 441: curl_off_t amount = data->progress.speeder[nowindex]-
! 442: data->progress.speeder[checkindex];
! 443:
! 444: if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
! 445: /* the 'amount' value is bigger than would fit in 32 bits if
! 446: multiplied with 1000, so we use the double math for this */
! 447: data->progress.current_speed = (curl_off_t)
! 448: ((double)amount/((double)span_ms/1000.0));
! 449: else
! 450: /* the 'amount' value is small enough to fit within 32 bits even
! 451: when multiplied with 1000 */
! 452: data->progress.current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
! 453: }
! 454: }
! 455: else
! 456: /* the first second we use the average */
! 457: data->progress.current_speed =
! 458: data->progress.ulspeed + data->progress.dlspeed;
! 459:
! 460: } /* Calculations end */
! 461: return timetoshow;
! 462: }
! 463:
! 464: #ifndef CURL_DISABLE_PROGRESS_METER
! 465: static void progress_meter(struct connectdata *conn)
! 466: {
! 467: struct Curl_easy *data = conn->data;
! 468: char max5[6][10];
! 469: curl_off_t dlpercen = 0;
! 470: curl_off_t ulpercen = 0;
! 471: curl_off_t total_percen = 0;
! 472: curl_off_t total_transfer;
! 473: curl_off_t total_expected_transfer;
! 474: char time_left[10];
! 475: char time_total[10];
! 476: char time_spent[10];
! 477: curl_off_t ulestimate = 0;
! 478: curl_off_t dlestimate = 0;
! 479: curl_off_t total_estimate;
! 480: curl_off_t timespent =
! 481: (curl_off_t)data->progress.timespent/1000000; /* seconds */
! 482:
! 483: if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
! 484: if(data->state.resume_from) {
! 485: fprintf(data->set.err,
! 486: "** Resuming transfer from byte position %"
! 487: CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
! 488: }
! 489: fprintf(data->set.err,
! 490: " %% Total %% Received %% Xferd Average Speed "
! 491: "Time Time Time Current\n"
! 492: " Dload Upload "
! 493: "Total Spent Left Speed\n");
! 494: data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
! 495: }
! 496:
! 497: /* Figure out the estimated time of arrival for the upload */
! 498: if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
! 499: (data->progress.ulspeed > CURL_OFF_T_C(0))) {
! 500: ulestimate = data->progress.size_ul / data->progress.ulspeed;
! 501:
! 502: if(data->progress.size_ul > CURL_OFF_T_C(10000))
! 503: ulpercen = data->progress.uploaded /
! 504: (data->progress.size_ul/CURL_OFF_T_C(100));
! 505: else if(data->progress.size_ul > CURL_OFF_T_C(0))
! 506: ulpercen = (data->progress.uploaded*100) /
! 507: data->progress.size_ul;
! 508: }
! 509:
! 510: /* ... and the download */
! 511: if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
! 512: (data->progress.dlspeed > CURL_OFF_T_C(0))) {
! 513: dlestimate = data->progress.size_dl / data->progress.dlspeed;
! 514:
! 515: if(data->progress.size_dl > CURL_OFF_T_C(10000))
! 516: dlpercen = data->progress.downloaded /
! 517: (data->progress.size_dl/CURL_OFF_T_C(100));
! 518: else if(data->progress.size_dl > CURL_OFF_T_C(0))
! 519: dlpercen = (data->progress.downloaded*100) /
! 520: data->progress.size_dl;
! 521: }
! 522:
! 523: /* Now figure out which of them is slower and use that one for the
! 524: total estimate! */
! 525: total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
! 526:
! 527: /* create the three time strings */
! 528: time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
! 529: time2str(time_total, total_estimate);
! 530: time2str(time_spent, timespent);
! 531:
! 532: /* Get the total amount of data expected to get transferred */
! 533: total_expected_transfer =
! 534: ((data->progress.flags & PGRS_UL_SIZE_KNOWN)?
! 535: data->progress.size_ul:data->progress.uploaded)+
! 536: ((data->progress.flags & PGRS_DL_SIZE_KNOWN)?
! 537: data->progress.size_dl:data->progress.downloaded);
! 538:
! 539: /* We have transferred this much so far */
! 540: total_transfer = data->progress.downloaded + data->progress.uploaded;
! 541:
! 542: /* Get the percentage of data transferred so far */
! 543: if(total_expected_transfer > CURL_OFF_T_C(10000))
! 544: total_percen = total_transfer /
! 545: (total_expected_transfer/CURL_OFF_T_C(100));
! 546: else if(total_expected_transfer > CURL_OFF_T_C(0))
! 547: total_percen = (total_transfer*100) / total_expected_transfer;
! 548:
! 549: fprintf(data->set.err,
! 550: "\r"
! 551: "%3" CURL_FORMAT_CURL_OFF_T " %s "
! 552: "%3" CURL_FORMAT_CURL_OFF_T " %s "
! 553: "%3" CURL_FORMAT_CURL_OFF_T " %s %s %s %s %s %s %s",
! 554: total_percen, /* 3 letters */ /* total % */
! 555: max5data(total_expected_transfer, max5[2]), /* total size */
! 556: dlpercen, /* 3 letters */ /* rcvd % */
! 557: max5data(data->progress.downloaded, max5[0]), /* rcvd size */
! 558: ulpercen, /* 3 letters */ /* xfer % */
! 559: max5data(data->progress.uploaded, max5[1]), /* xfer size */
! 560: max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
! 561: max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
! 562: time_total, /* 8 letters */ /* total time */
! 563: time_spent, /* 8 letters */ /* time spent */
! 564: time_left, /* 8 letters */ /* time left */
! 565: max5data(data->progress.current_speed, max5[5])
! 566: );
! 567:
! 568: /* we flush the output stream to make it appear as soon as possible */
! 569: fflush(data->set.err);
! 570: }
! 571: #else
! 572: /* progress bar disabled */
! 573: #define progress_meter(x) Curl_nop_stmt
! 574: #endif
! 575:
! 576:
! 577: /*
! 578: * Curl_pgrsUpdate() returns 0 for success or the value returned by the
! 579: * progress callback!
! 580: */
! 581: int Curl_pgrsUpdate(struct connectdata *conn)
! 582: {
! 583: struct Curl_easy *data = conn->data;
! 584: struct curltime now = Curl_now(); /* what time is it */
! 585: bool showprogress = progress_calc(conn, now);
! 586: if(!(data->progress.flags & PGRS_HIDE)) {
! 587: if(data->set.fxferinfo) {
! 588: int result;
! 589: /* There's a callback set, call that */
! 590: Curl_set_in_callback(data, true);
! 591: result = data->set.fxferinfo(data->set.progress_client,
! 592: data->progress.size_dl,
! 593: data->progress.downloaded,
! 594: data->progress.size_ul,
! 595: data->progress.uploaded);
! 596: Curl_set_in_callback(data, false);
! 597: if(result != CURL_PROGRESSFUNC_CONTINUE) {
! 598: if(result)
! 599: failf(data, "Callback aborted");
! 600: return result;
! 601: }
! 602: }
! 603: else if(data->set.fprogress) {
! 604: int result;
! 605: /* The older deprecated callback is set, call that */
! 606: Curl_set_in_callback(data, true);
! 607: result = data->set.fprogress(data->set.progress_client,
! 608: (double)data->progress.size_dl,
! 609: (double)data->progress.downloaded,
! 610: (double)data->progress.size_ul,
! 611: (double)data->progress.uploaded);
! 612: Curl_set_in_callback(data, false);
! 613: if(result != CURL_PROGRESSFUNC_CONTINUE) {
! 614: if(result)
! 615: failf(data, "Callback aborted");
! 616: return result;
! 617: }
! 618: }
! 619:
! 620: if(showprogress)
! 621: progress_meter(conn);
! 622: }
! 623:
! 624: return 0;
! 625: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>