Annotation of embedaddon/curl/src/tool_progress.c, revision 1.1.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>