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>