1 /*****************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * The contents of this file are subject to the Mozilla Public License
9 * Version 1.0 (the "License"); you may not use this file except in
10 * compliance with the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS"
14 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
15 * License for the specific language governing rights and limitations
18 * The Original Code is Curl.
20 * The Initial Developer of the Original Code is Daniel Stenberg.
22 * Portions created by the Initial Developer are Copyright (C) 1998.
23 * All Rights Reserved.
25 * ------------------------------------------------------------
27 * - Daniel Stenberg <Daniel.Stenberg@haxx.nu>
38 * ------------------------------------------------------------
39 ****************************************************************************/
44 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
45 #if defined(__MINGW32__)
52 * later we use _scrsize to determine the screen width, this emx library
53 * function needs stdlib.h to be included */
58 #include <curl/curl.h>
63 void time2str(char *r, int t)
66 int m = (t-(h*3600))/60;
67 int s = (t-(h*3600)-(m*60));
68 sprintf(r,"%2d:%02d:%02d",h,m,s);
71 /* The point of this function would be to return a string of the input data,
72 but never longer than 5 columns. Add suffix k, M, G when suitable... */
73 char *max5data(double bytes, char *max5)
75 #define ONE_KILOBYTE 1024
76 #define ONE_MEGABYTE (1024*1024)
79 sprintf(max5, "%5d", (int)bytes);
82 if(bytes < (9999*ONE_KILOBYTE)) {
83 sprintf(max5, "%4dk", (int)bytes/ONE_KILOBYTE);
86 if(bytes < (100*ONE_MEGABYTE)) {
87 /* 'XX.XM' is good as long as we're less than 100 megs */
88 sprintf(max5, "%2.1fM", bytes/ONE_MEGABYTE);
91 sprintf(max5, "%4dM", (int)bytes/ONE_MEGABYTE);
97 New proposed interface, 9th of February 2000:
99 pgrsStartNow() - sets start time
100 pgrsMode(type) - kind of display
101 pgrsSetDownloadSize(x) - known expected download size
102 pgrsSetUploadSize(x) - known expected upload size
103 pgrsSetDownloadCounter() - amount of data currently downloaded
104 pgrsSetUploadCounter() - amount of data currently uploaded
105 pgrsUpdate() - show progress
106 pgrsDone() - transfer complete
110 void pgrsDone(struct UrlData *data)
112 if(!(data->progress.flags & PGRS_HIDE)) {
113 data->progress.lastshow=0;
114 pgrsUpdate(data); /* the final (forced) update */
115 fprintf(stderr, "\n");
118 void pgrsMode(struct UrlData *data, int mode)
120 /* mode should include a hidden mode as well */
121 if(data->bits.hide_progress || data->bits.mute)
122 data->progress.flags |= PGRS_HIDE; /* don't show anything */
124 data->progress.mode = mode; /* store type */
129 void pgrsTime(struct UrlData *data, timerid timer)
136 case TIMER_NAMELOOKUP:
137 data->progress.t_nslookup = tvnow();
140 data->progress.t_connect = tvnow();
142 case TIMER_PRETRANSFER:
143 data->progress.t_pretransfer = tvnow();
145 case TIMER_POSTRANSFER:
146 /* this is the normal end-of-transfer thing */
151 void pgrsStartNow(struct UrlData *data)
153 data->progress.start = tvnow();
156 void pgrsSetDownloadCounter(struct UrlData *data, double size)
158 data->progress.downloaded = size;
161 void pgrsSetUploadCounter(struct UrlData *data, double size)
163 data->progress.uploaded = size;
166 void pgrsSetDownloadSize(struct UrlData *data, double size)
169 data->progress.size_dl = size;
170 data->progress.flags |= PGRS_DL_SIZE_KNOWN;
174 void pgrsSetUploadSize(struct UrlData *data, double size)
177 data->progress.size_ul = size;
178 data->progress.flags |= PGRS_UL_SIZE_KNOWN;
182 /* EXAMPLE OUTPUT to follow:
184 % Total % Received % Xferd Average Speed Time Curr.
185 Dload Upload Total Current Left Speed
186 100 12345 100 12345 100 12345 12345 12345 12:12:12 12:12:12 12:12:12 12345
190 int pgrsUpdate(struct UrlData *data)
197 double total_percen=0;
199 double total_transfer;
200 double total_expected_transfer;
204 static double speeder[ CURR_TIME ];
205 static int speeder_c=0;
207 int nowindex = speeder_c% CURR_TIME;
213 char time_current[10];
218 double total_estimate;
220 if(data->progress.flags & PGRS_HIDE)
221 ; /* We do enter this function even if we don't wanna see anything, since
222 this is were lots of the calculations are being made that will be used
223 even when not displayed! */
224 else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
225 if ( data->progress.mode == CURL_PROGRESS_STATS ) {
227 " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
228 " Dload Upload Total Current Left Speed\n");
230 data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
233 now = tvnow(); /* what time is it */
235 if(data->progress.lastshow == tvlong(now))
236 return 0; /* never update this more than once a second if the end isn't
238 data->progress.lastshow = now.tv_sec;
240 /* The exact time spent so far */
241 data->progress.timespent = tvdiff (now, data->progress.start);
243 /* The average download speed this far */
244 data->progress.dlspeed = data->progress.downloaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);
246 /* The average upload speed this far */
247 data->progress.ulspeed = data->progress.uploaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);
249 /* Let's do the "current speed" thing, which should use the fastest
250 of the dl/ul speeds */
252 speeder[ nowindex ] = data->progress.downloaded>data->progress.uploaded?
253 data->progress.downloaded:data->progress.uploaded;
254 speeder_c++; /* increase */
255 count = ((speeder_c>=CURR_TIME)?CURR_TIME:speeder_c) - 1;
256 checkindex = (speeder_c>=CURR_TIME)?speeder_c%CURR_TIME:0;
258 /* find out the average speed the last CURR_TIME seconds */
259 data->progress.current_speed =
260 (speeder[nowindex]-speeder[checkindex])/(count?count:1);
262 if(data->progress.flags & PGRS_HIDE)
264 else if(data->fprogress) {
265 return data->fprogress(data->progress_client,
266 data->progress.size_dl,
267 data->progress.downloaded,
268 data->progress.size_ul,
269 data->progress.uploaded);
272 /* Figure out the estimated time of arrival for the upload */
273 if(data->progress.flags & PGRS_UL_SIZE_KNOWN) {
274 if(!data->progress.ulspeed)
275 data->progress.ulspeed=1;
276 ulestimate = data->progress.size_ul / data->progress.ulspeed;
277 ulpercen = (data->progress.uploaded / data->progress.size_ul)*100;
280 /* ... and the download */
281 if(data->progress.flags & PGRS_DL_SIZE_KNOWN) {
282 if(!data->progress.dlspeed)
283 data->progress.dlspeed=1;
284 dlestimate = data->progress.size_dl / data->progress.dlspeed;
285 dlpercen = (data->progress.downloaded / data->progress.size_dl)*100;
288 /* Now figure out which of them that is slower and use for the for
290 total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
292 /* If we have a total estimate, we can display that and the expected
295 time2str(time_left, total_estimate-(int) data->progress.timespent);
296 time2str(time_total, total_estimate);
299 /* otherwise we blank those times */
300 strcpy(time_left, "--:--:--");
301 strcpy(time_total, "--:--:--");
303 /* The time spent so far is always known */
304 time2str(time_current, data->progress.timespent);
306 /* Get the total amount of data expected to get transfered */
307 total_expected_transfer =
308 (data->progress.flags & PGRS_UL_SIZE_KNOWN?
309 data->progress.size_ul:data->progress.uploaded)+
310 (data->progress.flags & PGRS_DL_SIZE_KNOWN?
311 data->progress.size_dl:data->progress.downloaded);
313 /* We have transfered this much so far */
314 total_transfer = data->progress.downloaded + data->progress.uploaded;
316 /* Get the percentage of data transfered so far */
317 if(total_expected_transfer)
318 total_percen=(double)(total_transfer/total_expected_transfer)*100;
321 "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
322 (int)total_percen, /* total % */
323 max5data(total_expected_transfer, max5[2]), /* total size */
324 (int)dlpercen, /* rcvd % */
325 max5data(data->progress.downloaded, max5[0]), /* rcvd size */
326 (int)ulpercen, /* xfer % */
327 max5data(data->progress.uploaded, max5[1]), /* xfer size */
329 max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
330 max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
331 time_total, /* total time */
332 time_current, /* current time */
333 time_left, /* time left */
334 max5data(data->progress.current_speed, max5[5]) /* current speed */
339 case CURL_PROGRESS_BAR:
340 /* original progress bar code by Lars Aas */
341 if (progressmax == -1) {
342 int prevblock = prev / 1024;
343 int thisblock = point / 1024;
344 while ( thisblock > prevblock ) {
345 fprintf( data->err, "#" );
354 float frac = (float) point / (float) progressmax;
355 float percent = frac * 100.0f;
356 int barwidth = width - 7;
357 int num = (int) (((float)barwidth) * frac);
359 for ( i = 0; i < num; i++ ) {
363 sprintf( format, "%%-%ds %%5.1f%%%%", barwidth );
364 sprintf( outline, format, line, percent );
365 fprintf( data->err, "\r%s", outline );
378 /* --- start of (the former) progress routines --- */
382 static int width = 0;
384 void ProgressInit(struct UrlData *data, int max/*, int options, int moremax*/)
391 if(data->conf&(CONF_NOPROGRESS|CONF_MUTE))
396 /* TODO: get terminal width through ansi escapes or something similar.
397 try to update width when xterm is resized... - 19990617 larsa */
400 * OS/2 users most likely won't have this env var set, and besides that
401 * we're using our own way to determine screen width */
402 if (curl_GetEnv("COLUMNS") != NULL)
403 width = atoi(curl_GetEnv("COLUMNS"));
408 * We use this emx library call to get the screen width, and subtract
409 * one from what we got in order to avoid a problem with the cursor
410 * advancing to the next line if we print a string that is as long as
411 * the screen is wide. */
414 width = scr_size[0] - 1;
421 if(progressmax <= LEAST_SIZE_PROGRESS) {
422 progressmax = -1; /* disable */
426 if ( data->progressmode == CURL_PROGRESS_STATS )
428 " %% Received Total Speed Estimated Time Left Curr.Speed\n");
432 void ProgressShow(struct UrlData *data,
433 int point, struct timeval start, struct timeval now, bool force)
435 switch ( data->progressmode ) {
436 case CURL_PROGRESS_STATS:
438 static long lastshow;
446 static int speeder[ CURR_TIME ];
447 static int speeder_c=0;
449 int nowindex = speeder_c% CURR_TIME;
453 if(!force && (point != progressmax) && (lastshow == tvlong(now)))
454 return; /* never update this more than once a second if the end isn't
457 spent = tvdiff (now, start);
458 speed = point/(spent!=0.0?spent:1.0);
462 /* point is where we are right now */
463 speeder[ nowindex ] = point;
464 speeder_c++; /* increase */
465 count = ((speeder_c>=CURR_TIME)?CURR_TIME:speeder_c) - 1;
466 checkindex = (speeder_c>=CURR_TIME)?speeder_c%CURR_TIME:0;
468 /* find out the average speed the last CURR_TIME seconds */
469 data->current_speed = (speeder[nowindex]-speeder[checkindex])/(count?count:1);
472 printf("NOW %d(%d) THEN %d(%d) DIFF %lf COUNT %d\n",
473 speeder[nowindex], nowindex,
474 speeder[checkindex], checkindex,
475 data->current_speed, count);
478 if(data->conf&(CONF_NOPROGRESS|CONF_MUTE))
481 if(-1 != progressmax) {
485 int estimate = progressmax/(int) speed;
487 time2str(left,estimate-(int) spent);
488 time2str(estim,estimate);
489 time2str(timespent,spent);
491 percen=(double)point/progressmax;
494 fprintf(stderr, "\r%3d %10d %10d %6.0lf %s %s %s %6.0lf ",
495 (int)percen, point, progressmax,
496 speed, estim, timespent, left, data->current_speed);
500 "\r%d bytes received in %.3lf seconds (%.0lf bytes/sec)",
501 point, spent, speed);
503 lastshow = now.tv_sec;
506 case CURL_PROGRESS_BAR: /* 19990617 larsa */
508 if (point == prev) break;
509 if (progressmax == -1) {
510 int prevblock = prev / 1024;
511 int thisblock = point / 1024;
512 while ( thisblock > prevblock ) {
513 fprintf( data->err, "#" );
521 float frac = (float) point / (float) progressmax;
522 float percent = frac * 100.0f;
523 int barwidth = width - 7;
524 int num = (int) (((float)barwidth) * frac);
526 for ( i = 0; i < num; i++ ) {
530 sprintf( format, "%%-%ds %%5.1f%%%%", barwidth );
531 sprintf( outline, format, line, percent );
532 fprintf( data->err, "\r%s", outline );
537 default: /* 19990617 larsa */
539 int prevblock = prev / 1024;
540 int thisblock = point / 1024;
541 if (prev == point) break;
542 while ( thisblock > prevblock ) {
543 fprintf( data->err, "#" );
552 void ProgressEnd(struct UrlData *data)
554 if(data->conf&(CONF_NOPROGRESS|CONF_MUTE))
556 fputs("\n", data->err);
559 /* --- end of progress routines --- */