1 /*****************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 2001, 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, "%4.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 connectdata *conn)
96 struct SessionHandle *data = conn->data;
97 if(!(data->progress.flags & PGRS_HIDE)) {
98 data->progress.lastshow=0;
99 Curl_pgrsUpdate(conn); /* the final (forced) update */
100 if(!data->progress.callback)
101 /* only output if we don't use progress callback */
102 fprintf(data->set.err, "\n");
106 void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
113 case TIMER_STARTSINGLE:
114 /* This is set at the start of a single fetch, there may be several
115 fetches within an operation, why we add all other times relative
117 data->progress.t_startsingle = Curl_tvnow();
120 case TIMER_NAMELOOKUP:
121 data->progress.t_nslookup +=
122 Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000;
125 data->progress.t_connect +=
126 Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000;
128 case TIMER_PRETRANSFER:
129 data->progress.t_pretransfer +=
130 Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000;
132 case TIMER_POSTRANSFER:
133 /* this is the normal end-of-transfer thing */
138 void Curl_pgrsStartNow(struct SessionHandle *data)
140 data->progress.speeder_c = 0; /* reset the progress meter display */
141 data->progress.start = Curl_tvnow();
144 void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, double size)
146 data->progress.downloaded = size;
149 void Curl_pgrsSetUploadCounter(struct SessionHandle *data, double size)
151 data->progress.uploaded = size;
154 void Curl_pgrsSetDownloadSize(struct SessionHandle *data, double size)
157 data->progress.size_dl = size;
158 data->progress.flags |= PGRS_DL_SIZE_KNOWN;
162 void Curl_pgrsSetUploadSize(struct SessionHandle *data, double size)
165 data->progress.size_ul = size;
166 data->progress.flags |= PGRS_UL_SIZE_KNOWN;
170 /* EXAMPLE OUTPUT to follow:
172 % Total % Received % Xferd Average Speed Time Curr.
173 Dload Upload Total Current Left Speed
174 100 12345 100 12345 100 12345 12345 12345 12:12:12 12:12:12 12:12:12 12345
178 int Curl_pgrsUpdate(struct connectdata *conn)
186 double total_percen=0;
188 double total_transfer;
189 double total_expected_transfer;
191 struct SessionHandle *data = conn->data;
193 int nowindex = data->progress.speeder_c% CURR_TIME;
196 int countindex; /* amount of seconds stored in the speeder array */
200 char time_current[10];
205 double total_estimate;
208 if(data->progress.flags & PGRS_HIDE)
209 ; /* We do enter this function even if we don't wanna see anything, since
210 this is were lots of the calculations are being made that will be used
211 even when not displayed! */
212 else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
213 if (!data->progress.callback) {
214 if(conn->resume_from)
215 fprintf(data->set.err, "** Resuming transfer from byte position %d\n",
217 fprintf(data->set.err,
218 " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
219 " Dload Upload Total Current Left Speed\n");
221 data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
224 now = Curl_tvnow(); /* what time is it */
226 /* The exact time spent so far (from the start) */
227 data->progress.timespent = Curl_tvdiff (now, data->progress.start)/1000;
229 /* The average download speed this far */
230 data->progress.dlspeed =
231 data->progress.downloaded/(data->progress.timespent?
232 data->progress.timespent:1);
234 /* The average upload speed this far */
235 data->progress.ulspeed =
236 data->progress.uploaded/(data->progress.timespent?
237 data->progress.timespent:1);
239 if(data->progress.lastshow == Curl_tvlong(now))
240 return 0; /* never update this more than once a second if the end isn't
242 data->progress.lastshow = now.tv_sec;
244 /* Let's do the "current speed" thing, which should use the fastest
245 of the dl/ul speeds. Store the fasted speed at entry 'nowindex'. */
246 data->progress.speeder[ nowindex ] =
247 data->progress.downloaded>data->progress.uploaded?
248 data->progress.downloaded:data->progress.uploaded;
250 /* remember the exact time for this moment */
251 data->progress.speeder_time [ nowindex ] = now;
253 /* advance our speeder_c counter, which is increased every time we get
254 here and we expect it to never wrap as 2^32 is a lot of seconds! */
255 data->progress.speeder_c++;
257 /* figure out how many index entries of data we have stored in our speeder
258 array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
259 transfer. Imagine, after one second we have filled in two entries,
260 after two seconds we've filled in three entries etc. */
261 countindex = ((data->progress.speeder_c>=CURR_TIME)?
262 CURR_TIME:data->progress.speeder_c) - 1;
264 /* first of all, we don't do this if there's no counted seconds yet */
268 /* Get the index position to compare with the 'nowindex' position.
269 Get the oldest entry possible. While we have less than CURR_TIME
270 entries, the first entry will remain the oldest. */
271 checkindex = (data->progress.speeder_c>=CURR_TIME)?
272 data->progress.speeder_c%CURR_TIME:0;
274 /* Figure out the exact time for the time span */
275 span_ms = Curl_tvdiff(now,
276 data->progress.speeder_time[checkindex]);
278 /* Calculate the average speed the last 'countindex' seconds */
279 data->progress.current_speed =
280 (data->progress.speeder[nowindex]-
281 data->progress.speeder[checkindex])/((double)span_ms/1000);
284 /* the first second we only have one speed information to use */
285 data->progress.current_speed = data->progress.speeder[nowindex];
287 if(data->progress.flags & PGRS_HIDE)
290 else if(data->set.fprogress) {
291 /* There's a callback set, so we call that instead of writing
292 anything ourselves. This really is the way to go. */
293 result= data->set.fprogress(data->set.progress_client,
294 data->progress.size_dl,
295 data->progress.downloaded,
296 data->progress.size_ul,
297 data->progress.uploaded);
299 failf(data, "Callback aborted");
303 /* Figure out the estimated time of arrival for the upload */
304 if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && data->progress.ulspeed){
305 ulestimate = data->progress.size_ul / data->progress.ulspeed;
306 ulpercen = (data->progress.uploaded / data->progress.size_ul)*100;
309 /* ... and the download */
310 if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && data->progress.dlspeed) {
311 dlestimate = data->progress.size_dl / data->progress.dlspeed;
312 dlpercen = (data->progress.downloaded / data->progress.size_dl)*100;
315 /* Now figure out which of them that is slower and use for the for
317 total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
320 /* If we have a total estimate, we can display that and the expected
323 time2str(time_left, total_estimate-(int) data->progress.timespent);
324 time2str(time_total, total_estimate);
327 /* otherwise we blank those times */
328 strcpy(time_left, "--:--:--");
329 strcpy(time_total, "--:--:--");
331 /* The time spent so far is always known */
332 time2str(time_current, data->progress.timespent);
334 /* Get the total amount of data expected to get transfered */
335 total_expected_transfer =
336 (data->progress.flags & PGRS_UL_SIZE_KNOWN?
337 data->progress.size_ul:data->progress.uploaded)+
338 (data->progress.flags & PGRS_DL_SIZE_KNOWN?
339 data->progress.size_dl:data->progress.downloaded);
341 /* We have transfered this much so far */
342 total_transfer = data->progress.downloaded + data->progress.uploaded;
344 /* Get the percentage of data transfered so far */
345 if(total_expected_transfer)
346 total_percen=(double)(total_transfer/total_expected_transfer)*100;
348 fprintf(data->set.err,
349 "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
350 (int)total_percen, /* total % */
351 max5data(total_expected_transfer, max5[2]), /* total size */
352 (int)dlpercen, /* rcvd % */
353 max5data(data->progress.downloaded, max5[0]), /* rcvd size */
354 (int)ulpercen, /* xfer % */
355 max5data(data->progress.uploaded, max5[1]), /* xfer size */
357 max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
358 max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
359 time_total, /* total time */
360 time_current, /* current time */
361 time_left, /* time left */
362 max5data(data->progress.current_speed, max5[5]) /* current speed */
365 /* we flush the output stream to make it appear as soon as possible */
366 fflush(data->set.err);
373 * eval: (load-file "../curl-mode.el")
376 * vim: et sw=2 ts=2 sts=2 tw=78