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@haxx.se>
38 * ------------------------------------------------------------
39 ****************************************************************************/
45 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
46 #if defined(__MINGW32__)
53 * later we use _scrsize to determine the screen width, this emx library
54 * function needs stdlib.h to be included */
59 #include <curl/curl.h>
65 void time2str(char *r, int t)
68 int m = (t-(h*3600))/60;
69 int s = (t-(h*3600)-(m*60));
70 sprintf(r,"%2d:%02d:%02d",h,m,s);
73 /* The point of this function would be to return a string of the input data,
74 but never longer than 5 columns. Add suffix k, M, G when suitable... */
75 char *max5data(double bytes, char *max5)
77 #define ONE_KILOBYTE 1024
78 #define ONE_MEGABYTE (1024*1024)
81 sprintf(max5, "%5d", (int)bytes);
84 if(bytes < (9999*ONE_KILOBYTE)) {
85 sprintf(max5, "%4dk", (int)bytes/ONE_KILOBYTE);
88 if(bytes < (100*ONE_MEGABYTE)) {
89 /* 'XX.XM' is good as long as we're less than 100 megs */
90 sprintf(max5, "%2.1fM", bytes/ONE_MEGABYTE);
93 sprintf(max5, "%4dM", (int)bytes/ONE_MEGABYTE);
99 New proposed interface, 9th of February 2000:
101 pgrsStartNow() - sets start time
102 pgrsSetDownloadSize(x) - known expected download size
103 pgrsSetUploadSize(x) - known expected upload size
104 pgrsSetDownloadCounter() - amount of data currently downloaded
105 pgrsSetUploadCounter() - amount of data currently uploaded
106 pgrsUpdate() - show progress
107 pgrsDone() - transfer complete
111 void pgrsDone(struct UrlData *data)
113 if(!(data->progress.flags & PGRS_HIDE)) {
114 data->progress.lastshow=0;
115 pgrsUpdate(data); /* the final (forced) update */
116 fprintf(data->err, "\n");
120 void pgrsTime(struct UrlData *data, timerid timer)
127 case TIMER_STARTSINGLE:
128 /* This is set at the start of a single fetch, there may be several
129 fetches within an operation, why we add all other times relative
131 data->progress.t_startsingle = tvnow();
134 case TIMER_NAMELOOKUP:
135 data->progress.t_nslookup += tvdiff(tvnow(),
136 data->progress.t_startsingle);
139 data->progress.t_connect += tvdiff(tvnow(),
140 data->progress.t_startsingle);
142 case TIMER_PRETRANSFER:
143 data->progress.t_pretransfer += tvdiff(tvnow(),
144 data->progress.t_startsingle);
146 case TIMER_POSTRANSFER:
147 /* this is the normal end-of-transfer thing */
152 void pgrsStartNow(struct UrlData *data)
154 data->progress.start = tvnow();
157 void pgrsSetDownloadCounter(struct UrlData *data, double size)
159 data->progress.downloaded = size;
162 void pgrsSetUploadCounter(struct UrlData *data, double size)
164 data->progress.uploaded = size;
167 void pgrsSetDownloadSize(struct UrlData *data, double size)
170 data->progress.size_dl = size;
171 data->progress.flags |= PGRS_DL_SIZE_KNOWN;
175 void pgrsSetUploadSize(struct UrlData *data, double size)
178 data->progress.size_ul = size;
179 data->progress.flags |= PGRS_UL_SIZE_KNOWN;
183 /* EXAMPLE OUTPUT to follow:
185 % Total % Received % Xferd Average Speed Time Curr.
186 Dload Upload Total Current Left Speed
187 100 12345 100 12345 100 12345 12345 12345 12:12:12 12:12:12 12:12:12 12345
191 int pgrsUpdate(struct UrlData *data)
199 double total_percen=0;
201 double total_transfer;
202 double total_expected_transfer;
204 int nowindex = data->progress.speeder_c% CURR_TIME;
210 char time_current[10];
215 double total_estimate;
217 if(data->progress.flags & PGRS_HIDE)
218 ; /* We do enter this function even if we don't wanna see anything, since
219 this is were lots of the calculations are being made that will be used
220 even when not displayed! */
221 else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
222 if (!data->progress.callback) {
224 " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
225 " Dload Upload Total Current Left Speed\n");
227 data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
230 now = tvnow(); /* what time is it */
232 if(data->progress.lastshow == tvlong(now))
233 return 0; /* never update this more than once a second if the end isn't
235 data->progress.lastshow = now.tv_sec;
237 /* The exact time spent so far */
238 data->progress.timespent = tvdiff (now, data->progress.start);
240 /* The average download speed this far */
241 data->progress.dlspeed = data->progress.downloaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);
243 /* The average upload speed this far */
244 data->progress.ulspeed = data->progress.uploaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);
246 /* Let's do the "current speed" thing, which should use the fastest
247 of the dl/ul speeds */
249 data->progress.speeder[ nowindex ] =
250 data->progress.downloaded>data->progress.uploaded?
251 data->progress.downloaded:data->progress.uploaded;
252 data->progress.speeder_c++; /* increase */
253 count = ((data->progress.speeder_c>=CURR_TIME)?
254 CURR_TIME:data->progress.speeder_c) - 1;
255 checkindex = (data->progress.speeder_c>=CURR_TIME)?
256 data->progress.speeder_c%CURR_TIME:0;
258 /* find out the average speed the last CURR_TIME seconds */
259 data->progress.current_speed =
260 (data->progress.speeder[nowindex]-
261 data->progress.speeder[checkindex])/(count?count:1);
263 if(data->progress.flags & PGRS_HIDE)
265 else if(data->fprogress) {
266 result= data->fprogress(data->progress_client,
267 data->progress.size_dl,
268 data->progress.downloaded,
269 data->progress.size_ul,
270 data->progress.uploaded);
272 failf(data, "Callback aborted");
276 /* Figure out the estimated time of arrival for the upload */
277 if(data->progress.flags & PGRS_UL_SIZE_KNOWN) {
278 if(!data->progress.ulspeed)
279 data->progress.ulspeed=1;
280 ulestimate = data->progress.size_ul / data->progress.ulspeed;
281 ulpercen = (data->progress.uploaded / data->progress.size_ul)*100;
284 /* ... and the download */
285 if(data->progress.flags & PGRS_DL_SIZE_KNOWN) {
286 if(!data->progress.dlspeed)
287 data->progress.dlspeed=1;
288 dlestimate = data->progress.size_dl / data->progress.dlspeed;
289 dlpercen = (data->progress.downloaded / data->progress.size_dl)*100;
292 /* Now figure out which of them that is slower and use for the for
294 total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
297 /* If we have a total estimate, we can display that and the expected
300 time2str(time_left, total_estimate-(int) data->progress.timespent);
301 time2str(time_total, total_estimate);
304 /* otherwise we blank those times */
305 strcpy(time_left, "--:--:--");
306 strcpy(time_total, "--:--:--");
308 /* The time spent so far is always known */
309 time2str(time_current, data->progress.timespent);
311 /* Get the total amount of data expected to get transfered */
312 total_expected_transfer =
313 (data->progress.flags & PGRS_UL_SIZE_KNOWN?
314 data->progress.size_ul:data->progress.uploaded)+
315 (data->progress.flags & PGRS_DL_SIZE_KNOWN?
316 data->progress.size_dl:data->progress.downloaded);
318 /* We have transfered this much so far */
319 total_transfer = data->progress.downloaded + data->progress.uploaded;
321 /* Get the percentage of data transfered so far */
322 if(total_expected_transfer)
323 total_percen=(double)(total_transfer/total_expected_transfer)*100;
326 "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
327 (int)total_percen, /* total % */
328 max5data(total_expected_transfer, max5[2]), /* total size */
329 (int)dlpercen, /* rcvd % */
330 max5data(data->progress.downloaded, max5[0]), /* rcvd size */
331 (int)ulpercen, /* xfer % */
332 max5data(data->progress.uploaded, max5[1]), /* xfer size */
334 max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
335 max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
336 time_total, /* total time */
337 time_current, /* current time */
338 time_left, /* time left */
339 max5data(data->progress.current_speed, max5[5]) /* current speed */