Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/progress.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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) | |
| 598 failf(data, "Callback aborted"); | |
| 599 return result; | |
| 600 } | |
| 601 if(data->set.fprogress) { | |
| 602 int result; | |
| 603 /* The older deprecated callback is set, call that */ | |
| 604 Curl_set_in_callback(data, true); | |
| 605 result = data->set.fprogress(data->set.progress_client, | |
| 606 (double)data->progress.size_dl, | |
| 607 (double)data->progress.downloaded, | |
| 608 (double)data->progress.size_ul, | |
| 609 (double)data->progress.uploaded); | |
| 610 Curl_set_in_callback(data, false); | |
| 611 if(result) | |
| 612 failf(data, "Callback aborted"); | |
| 613 return result; | |
| 614 } | |
| 615 | |
| 616 if(showprogress) | |
| 617 progress_meter(conn); | |
| 618 } | |
| 619 | |
| 620 return 0; | |
| 621 } |
