00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026 #include <string.h>
00027 #include <time.h>
00028
00029 #if defined(__EMX__)
00030 #include <stdlib.h>
00031 #endif
00032
00033 #include <curl/curl.h>
00034 #include "urldata.h"
00035 #include "sendf.h"
00036 #include "progress.h"
00037
00038 #define _MPRINTF_REPLACE
00039 #include <curl/mprintf.h>
00040
00041
00042
00043 static void time2str(char *r, long t)
00044 {
00045 long h;
00046 if(!t) {
00047 strcpy(r, "--:--:--");
00048 return;
00049 }
00050 h = (t/3600);
00051 if(h <= 99) {
00052 long m = (t-(h*3600))/60;
00053 long s = (t-(h*3600)-(m*60));
00054 snprintf(r, 9, "%2ld:%02ld:%02ld",h,m,s);
00055 }
00056 else {
00057
00058
00059 if(h/24 <= 999)
00060 snprintf(r, 9, "%3ldd %02ldh", h/24, h-(h/24)*24);
00061 else
00062 snprintf(r, 9, "%7ldd", h/24);
00063 }
00064 }
00065
00066
00067
00068
00069 static char *max5data(curl_off_t bytes, char *max5)
00070 {
00071 #define ONE_KILOBYTE 1024
00072 #define ONE_MEGABYTE (1024* ONE_KILOBYTE)
00073 #define ONE_GIGABYTE (1024* ONE_MEGABYTE)
00074 #define ONE_TERABYTE ((curl_off_t)1024* ONE_GIGABYTE)
00075 #define ONE_PETABYTE ((curl_off_t)1024* ONE_TERABYTE)
00076
00077 if(bytes < 100000) {
00078 snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes);
00079 }
00080 else if(bytes < (10000*ONE_KILOBYTE)) {
00081 snprintf(max5, 6, "%4" FORMAT_OFF_T "k", (curl_off_t)(bytes/ONE_KILOBYTE));
00082 }
00083 else if(bytes < (100*ONE_MEGABYTE)) {
00084
00085 snprintf(max5, 6, "%2d.%0dM",
00086 (int)(bytes/ONE_MEGABYTE),
00087 (int)(bytes%ONE_MEGABYTE)/(ONE_MEGABYTE/10) );
00088 }
00089 #if SIZEOF_CURL_OFF_T > 4
00090 else if(bytes < ( (curl_off_t)10000*ONE_MEGABYTE))
00091
00092 snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
00093
00094 else if(bytes < (curl_off_t)100*ONE_GIGABYTE)
00095
00096 snprintf(max5, 6, "%2d.%0dG",
00097 (int)(bytes/ONE_GIGABYTE),
00098 (int)(bytes%ONE_GIGABYTE)/(ONE_GIGABYTE/10) );
00099
00100 else if(bytes < (curl_off_t)10000 * ONE_GIGABYTE)
00101
00102 snprintf(max5, 6, "%4dG", (int)(bytes/ONE_GIGABYTE));
00103
00104 else if(bytes < (curl_off_t)10000 * ONE_TERABYTE)
00105
00106 snprintf(max5, 6, "%4dT", (int)(bytes/ONE_TERABYTE));
00107 else {
00108
00109 snprintf(max5, 6, "%4dP", (int)(bytes/ONE_PETABYTE));
00110
00111
00112
00113 }
00114
00115 #else
00116 else
00117 snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
00118 #endif
00119
00120 return max5;
00121 }
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 void Curl_pgrsDone(struct connectdata *conn)
00138 {
00139 struct SessionHandle *data = conn->data;
00140 data->progress.lastshow=0;
00141 Curl_pgrsUpdate(conn);
00142
00143 data->progress.speeder_c = 0;
00144 }
00145
00146
00147 void Curl_pgrsResetTimes(struct SessionHandle *data)
00148 {
00149 data->progress.t_nslookup = 0.0;
00150 data->progress.t_connect = 0.0;
00151 data->progress.t_pretransfer = 0.0;
00152 data->progress.t_starttransfer = 0.0;
00153 }
00154
00155 void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
00156 {
00157 switch(timer) {
00158 default:
00159 case TIMER_NONE:
00160
00161 break;
00162 case TIMER_STARTSINGLE:
00163
00164 data->progress.t_startsingle = Curl_tvnow();
00165 break;
00166
00167 case TIMER_NAMELOOKUP:
00168 data->progress.t_nslookup =
00169 Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
00170 break;
00171 case TIMER_CONNECT:
00172 data->progress.t_connect =
00173 Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
00174 break;
00175 case TIMER_PRETRANSFER:
00176 data->progress.t_pretransfer =
00177 Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
00178 break;
00179 case TIMER_STARTTRANSFER:
00180 data->progress.t_starttransfer =
00181 Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
00182 break;
00183 case TIMER_POSTRANSFER:
00184
00185 break;
00186 case TIMER_REDIRECT:
00187 data->progress.t_redirect =
00188 Curl_tvdiff_secs(Curl_tvnow(), data->progress.start);
00189 break;
00190 }
00191 }
00192
00193 void Curl_pgrsStartNow(struct SessionHandle *data)
00194 {
00195 data->progress.speeder_c = 0;
00196 data->progress.start = Curl_tvnow();
00197 }
00198
00199 void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
00200 {
00201 data->progress.downloaded = size;
00202 }
00203
00204 void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
00205 {
00206 data->progress.uploaded = size;
00207 }
00208
00209 void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
00210 {
00211 data->progress.size_dl = size;
00212 if(size > 0)
00213 data->progress.flags |= PGRS_DL_SIZE_KNOWN;
00214 else
00215 data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
00216 }
00217
00218 void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
00219 {
00220 data->progress.size_ul = size;
00221 if(size > 0)
00222 data->progress.flags |= PGRS_UL_SIZE_KNOWN;
00223 else
00224 data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
00225 }
00226
00227 int Curl_pgrsUpdate(struct connectdata *conn)
00228 {
00229 struct timeval now;
00230 int result;
00231 char max5[6][10];
00232 int dlpercen=0;
00233 int ulpercen=0;
00234 int total_percen=0;
00235 curl_off_t total_transfer;
00236 curl_off_t total_expected_transfer;
00237 long timespent;
00238 struct SessionHandle *data = conn->data;
00239 int nowindex = data->progress.speeder_c% CURR_TIME;
00240 int checkindex;
00241 int countindex;
00242 char time_left[10];
00243 char time_total[10];
00244 char time_spent[10];
00245 long ulestimate=0;
00246 long dlestimate=0;
00247 long total_estimate;
00248 bool shownow=FALSE;
00249
00250 now = Curl_tvnow();
00251
00252
00253 data->progress.timespent =
00254 (double)(now.tv_sec - data->progress.start.tv_sec) +
00255 (double)(now.tv_usec - data->progress.start.tv_usec)/1000000.0;
00256 timespent = (long)data->progress.timespent;
00257
00258
00259 data->progress.dlspeed = (curl_off_t)
00260 ((double)data->progress.downloaded/
00261 (data->progress.timespent>0?data->progress.timespent:1));
00262
00263
00264 data->progress.ulspeed = (curl_off_t)
00265 ((double)data->progress.uploaded/
00266 (data->progress.timespent>0?data->progress.timespent:1));
00267
00268
00269 if(data->progress.lastshow != (long)now.tv_sec) {
00270 shownow = TRUE;
00271
00272 data->progress.lastshow = now.tv_sec;
00273
00274
00275
00276 data->progress.speeder[ nowindex ] =
00277 data->progress.downloaded>data->progress.uploaded?
00278 data->progress.downloaded:data->progress.uploaded;
00279
00280
00281 data->progress.speeder_time [ nowindex ] = now;
00282
00283
00284
00285 data->progress.speeder_c++;
00286
00287
00288
00289
00290
00291 countindex = ((data->progress.speeder_c>=CURR_TIME)?
00292 CURR_TIME:data->progress.speeder_c) - 1;
00293
00294
00295 if(countindex) {
00296 long span_ms;
00297
00298
00299
00300
00301 checkindex = (data->progress.speeder_c>=CURR_TIME)?
00302 data->progress.speeder_c%CURR_TIME:0;
00303
00304
00305 span_ms = Curl_tvdiff(now,
00306 data->progress.speeder_time[checkindex]);
00307 if(0 == span_ms)
00308 span_ms=1;
00309
00310
00311 {
00312 curl_off_t amount = data->progress.speeder[nowindex]-
00313 data->progress.speeder[checkindex];
00314
00315 if(amount > 4294967 )
00316
00317
00318 data->progress.current_speed = (curl_off_t)
00319 ((double)amount/((double)span_ms/1000.0));
00320 else
00321
00322
00323 data->progress.current_speed = amount*1000/span_ms;
00324 }
00325 }
00326 else
00327
00328 data->progress.current_speed =
00329 (data->progress.ulspeed>data->progress.dlspeed)?
00330 data->progress.ulspeed:data->progress.dlspeed;
00331
00332 }
00333
00334 if(!(data->progress.flags & PGRS_HIDE)) {
00335
00336
00337
00338 if(data->set.fprogress) {
00339
00340
00341 result= data->set.fprogress(data->set.progress_client,
00342 (double)data->progress.size_dl,
00343 (double)data->progress.downloaded,
00344 (double)data->progress.size_ul,
00345 (double)data->progress.uploaded);
00346 if(result)
00347 failf(data, "Callback aborted");
00348 return result;
00349 }
00350
00351 if(!shownow)
00352
00353 return 0;
00354
00355
00356
00357
00358 if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
00359 if(data->reqdata.resume_from) {
00360 fprintf(data->set.err,
00361 "** Resuming transfer from byte position %" FORMAT_OFF_T
00362 "\n",
00363 data->reqdata.resume_from);
00364 }
00365 fprintf(data->set.err,
00366 " %% Total %% Received %% Xferd Average Speed Time Time Time Current\n"
00367 " Dload Upload Total Spent Left Speed\n");
00368 data->progress.flags |= PGRS_HEADERS_OUT;
00369 }
00370
00371
00372 if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
00373 (data->progress.ulspeed>0) &&
00374 (data->progress.size_ul > 100) ) {
00375 ulestimate = (long)(data->progress.size_ul / data->progress.ulspeed);
00376 ulpercen = (int)(100*(data->progress.uploaded/100) /
00377 (data->progress.size_ul/100) );
00378 }
00379
00380
00381 if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
00382 (data->progress.dlspeed>0) &&
00383 (data->progress.size_dl>100)) {
00384 dlestimate = (long)(data->progress.size_dl / data->progress.dlspeed);
00385 dlpercen = (int)(100*(data->progress.downloaded/100) /
00386 (data->progress.size_dl/100));
00387 }
00388
00389
00390
00391 total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
00392
00393
00394 time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
00395 time2str(time_total, total_estimate);
00396 time2str(time_spent, timespent);
00397
00398
00399 total_expected_transfer =
00400 (data->progress.flags & PGRS_UL_SIZE_KNOWN?
00401 data->progress.size_ul:data->progress.uploaded)+
00402 (data->progress.flags & PGRS_DL_SIZE_KNOWN?
00403 data->progress.size_dl:data->progress.downloaded);
00404
00405
00406 total_transfer = data->progress.downloaded + data->progress.uploaded;
00407
00408
00409 if(total_expected_transfer > 100)
00410 total_percen=(int)(100*(total_transfer/100) /
00411 (total_expected_transfer/100) );
00412
00413 fprintf(data->set.err,
00414 "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
00415 total_percen,
00416 max5data(total_expected_transfer, max5[2]),
00417 dlpercen,
00418 max5data(data->progress.downloaded, max5[0]),
00419 ulpercen,
00420 max5data(data->progress.uploaded, max5[1]),
00421 max5data(data->progress.dlspeed, max5[3]),
00422 max5data(data->progress.ulspeed, max5[4]),
00423 time_total,
00424 time_spent,
00425 time_left,
00426 max5data(data->progress.current_speed, max5[5])
00427 );
00428
00429
00430 fflush(data->set.err);
00431
00432 }
00433
00434 return 0;
00435 }