1 /*****************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * In order to be useful for every potential user, curl and libcurl are
11 * dual-licensed under the MPL and the MIT/X-derivate licenses.
13 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
14 * copies of the Software, and permit persons to whom the Software is
15 * furnished to do so, under the terms of the MPL or the MIT/X-derivate
16 * licenses. You may pick one of these licenses.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
22 *****************************************************************************/
28 #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
29 #if defined(__MINGW32__)
36 * later we use _scrsize to determine the screen width, this emx library
37 * function needs stdlib.h to be included */
42 #include <curl/curl.h>
48 static void time2str(char *r, int t)
51 int m = (t-(h*3600))/60;
52 int s = (t-(h*3600)-(m*60));
53 sprintf(r,"%2d:%02d:%02d",h,m,s);
56 /* The point of this function would be to return a string of the input data,
57 but never longer than 5 columns. Add suffix k, M, G when suitable... */
58 static char *max5data(double bytes, char *max5)
60 #define ONE_KILOBYTE 1024
61 #define ONE_MEGABYTE (1024*1024)
64 sprintf(max5, "%5d", (int)bytes);
67 if(bytes < (9999*ONE_KILOBYTE)) {
68 sprintf(max5, "%4dk", (int)bytes/ONE_KILOBYTE);
71 if(bytes < (100*ONE_MEGABYTE)) {
72 /* 'XX.XM' is good as long as we're less than 100 megs */
73 sprintf(max5, "%2.1fM", bytes/ONE_MEGABYTE);
76 sprintf(max5, "%4dM", (int)bytes/ONE_MEGABYTE);
82 New proposed interface, 9th of February 2000:
84 pgrsStartNow() - sets start time
85 pgrsSetDownloadSize(x) - known expected download size
86 pgrsSetUploadSize(x) - known expected upload size
87 pgrsSetDownloadCounter() - amount of data currently downloaded
88 pgrsSetUploadCounter() - amount of data currently uploaded
89 pgrsUpdate() - show progress
90 pgrsDone() - transfer complete
94 void Curl_pgrsDone(struct UrlData *data)
96 if(!(data->progress.flags & PGRS_HIDE)) {
97 data->progress.lastshow=0;
98 Curl_pgrsUpdate(data); /* the final (forced) update */
99 fprintf(data->err, "\n");
103 void Curl_pgrsTime(struct UrlData *data, timerid timer)
110 case TIMER_STARTSINGLE:
111 /* This is set at the start of a single fetch, there may be several
112 fetches within an operation, why we add all other times relative
114 data->progress.t_startsingle = Curl_tvnow();
117 case TIMER_NAMELOOKUP:
118 data->progress.t_nslookup += Curl_tvdiff(Curl_tvnow(),
119 data->progress.t_startsingle);
122 data->progress.t_connect += Curl_tvdiff(Curl_tvnow(),
123 data->progress.t_startsingle);
125 case TIMER_PRETRANSFER:
126 data->progress.t_pretransfer += Curl_tvdiff(Curl_tvnow(),
127 data->progress.t_startsingle);
129 case TIMER_POSTRANSFER:
130 /* this is the normal end-of-transfer thing */
135 void Curl_pgrsStartNow(struct UrlData *data)
137 data->progress.start = Curl_tvnow();
140 void Curl_pgrsSetDownloadCounter(struct UrlData *data, double size)
142 data->progress.downloaded = size;
145 void Curl_pgrsSetUploadCounter(struct UrlData *data, double size)
147 data->progress.uploaded = size;
150 void Curl_pgrsSetDownloadSize(struct UrlData *data, double size)
153 data->progress.size_dl = size;
154 data->progress.flags |= PGRS_DL_SIZE_KNOWN;
158 void Curl_pgrsSetUploadSize(struct UrlData *data, double size)
161 data->progress.size_ul = size;
162 data->progress.flags |= PGRS_UL_SIZE_KNOWN;
166 /* EXAMPLE OUTPUT to follow:
168 % Total % Received % Xferd Average Speed Time Curr.
169 Dload Upload Total Current Left Speed
170 100 12345 100 12345 100 12345 12345 12345 12:12:12 12:12:12 12:12:12 12345
174 int Curl_pgrsUpdate(struct UrlData *data)
182 double total_percen=0;
184 double total_transfer;
185 double total_expected_transfer;
187 int nowindex = data->progress.speeder_c% CURR_TIME;
193 char time_current[10];
198 double total_estimate;
200 if(data->progress.flags & PGRS_HIDE)
201 ; /* We do enter this function even if we don't wanna see anything, since
202 this is were lots of the calculations are being made that will be used
203 even when not displayed! */
204 else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
205 if (!data->progress.callback) {
207 " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
208 " Dload Upload Total Current Left Speed\n");
210 data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
213 now = Curl_tvnow(); /* what time is it */
215 /* The exact time spent so far */
216 data->progress.timespent = Curl_tvdiff (now, data->progress.start);
218 if(data->progress.lastshow == Curl_tvlong(now))
219 return 0; /* never update this more than once a second if the end isn't
221 data->progress.lastshow = now.tv_sec;
223 /* The average download speed this far */
224 data->progress.dlspeed = data->progress.downloaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);
226 /* The average upload speed this far */
227 data->progress.ulspeed = data->progress.uploaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);
229 /* Let's do the "current speed" thing, which should use the fastest
230 of the dl/ul speeds */
232 data->progress.speeder[ nowindex ] =
233 data->progress.downloaded>data->progress.uploaded?
234 data->progress.downloaded:data->progress.uploaded;
235 data->progress.speeder_c++; /* increase */
236 count = ((data->progress.speeder_c>=CURR_TIME)?
237 CURR_TIME:data->progress.speeder_c) - 1;
238 checkindex = (data->progress.speeder_c>=CURR_TIME)?
239 data->progress.speeder_c%CURR_TIME:0;
241 /* find out the average speed the last CURR_TIME seconds */
242 data->progress.current_speed =
243 (data->progress.speeder[nowindex]-
244 data->progress.speeder[checkindex])/(count?count:1);
246 if(data->progress.flags & PGRS_HIDE)
248 else if(data->fprogress) {
249 result= data->fprogress(data->progress_client,
250 data->progress.size_dl,
251 data->progress.downloaded,
252 data->progress.size_ul,
253 data->progress.uploaded);
255 failf(data, "Callback aborted");
259 /* Figure out the estimated time of arrival for the upload */
260 if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && data->progress.ulspeed){
261 ulestimate = data->progress.size_ul / data->progress.ulspeed;
262 ulpercen = (data->progress.uploaded / data->progress.size_ul)*100;
265 /* ... and the download */
266 if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && data->progress.dlspeed) {
267 dlestimate = data->progress.size_dl / data->progress.dlspeed;
268 dlpercen = (data->progress.downloaded / data->progress.size_dl)*100;
271 /* Now figure out which of them that is slower and use for the for
273 total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
276 /* If we have a total estimate, we can display that and the expected
279 time2str(time_left, total_estimate-(int) data->progress.timespent);
280 time2str(time_total, total_estimate);
283 /* otherwise we blank those times */
284 strcpy(time_left, "--:--:--");
285 strcpy(time_total, "--:--:--");
287 /* The time spent so far is always known */
288 time2str(time_current, data->progress.timespent);
290 /* Get the total amount of data expected to get transfered */
291 total_expected_transfer =
292 (data->progress.flags & PGRS_UL_SIZE_KNOWN?
293 data->progress.size_ul:data->progress.uploaded)+
294 (data->progress.flags & PGRS_DL_SIZE_KNOWN?
295 data->progress.size_dl:data->progress.downloaded);
297 /* We have transfered this much so far */
298 total_transfer = data->progress.downloaded + data->progress.uploaded;
300 /* Get the percentage of data transfered so far */
301 if(total_expected_transfer)
302 total_percen=(double)(total_transfer/total_expected_transfer)*100;
305 "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
306 (int)total_percen, /* total % */
307 max5data(total_expected_transfer, max5[2]), /* total size */
308 (int)dlpercen, /* rcvd % */
309 max5data(data->progress.downloaded, max5[0]), /* rcvd size */
310 (int)ulpercen, /* xfer % */
311 max5data(data->progress.uploaded, max5[1]), /* xfer size */
313 max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
314 max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
315 time_total, /* total time */
316 time_current, /* current time */
317 time_left, /* time left */
318 max5data(data->progress.current_speed, max5[5]) /* current speed */