doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
progress.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * $Id: progress.c,v 1.57 2004/03/11 21:48:15 bagder Exp $
22  ***************************************************************************/
23 
24 #include "setup.h"
25 
26 #include <string.h>
27 #include <time.h>
28 
29 /* 20000318 mgs
30  * later we use _scrsize to determine the screen width, this emx library
31  * function needs stdlib.h to be included */
32 #if defined(__EMX__)
33 #include <stdlib.h>
34 #endif
35 
36 #include <curl/curl.h>
37 #include "urldata.h"
38 #include "sendf.h"
39 
40 #include "progress.h"
41 
42 #define _MPRINTF_REPLACE /* use our functions only */
43 #include <curl/mprintf.h>
44 
45 
46 static void time2str(char *r, int t)
47 {
48  int h = (t/3600);
49  int m = (t-(h*3600))/60;
50  int s = (t-(h*3600)-(m*60));
51  sprintf(r,"%2d:%02d:%02d",h,m,s);
52 }
53 
54 /* The point of this function would be to return a string of the input data,
55  but never longer than 5 columns. Add suffix k, M, G when suitable... */
56 static char *max5data(curl_off_t bytes, char *max5)
57 {
58 #define ONE_KILOBYTE 1024
59 #define ONE_MEGABYTE (1024*1024)
60 #define ONE_GIGABYTE (1024*1024*1024)
61 
62  if(bytes < 100000) {
63  sprintf(max5, "%5" FORMAT_OFF_T, bytes);
64  }
65  else if(bytes < (10000*ONE_KILOBYTE)) {
66  sprintf(max5, "%4" FORMAT_OFF_T "k", (curl_off_t)(bytes/ONE_KILOBYTE));
67  }
68  else if(bytes < (100*ONE_MEGABYTE)) {
69  /* 'XX.XM' is good as long as we're less than 100 megs */
70  sprintf(max5, "%2d.%0dM",
71  (int)(bytes/ONE_MEGABYTE),
72  (int)(bytes%ONE_MEGABYTE)/(ONE_MEGABYTE/10) );
73  }
74 #if SIZEOF_CURL_OFF_T > 4
75  else if(bytes < ((curl_off_t)10000*ONE_MEGABYTE)) {
76  sprintf(max5, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
77  }
78  else
79  /* 10000 MB - 8589934587 GB !! */
80  sprintf(max5, "%2d.%0dG",
81  (int)(bytes/ONE_GIGABYTE),
82  (int)(bytes%ONE_GIGABYTE)/(ONE_GIGABYTE/10) );
83 #else
84  else
85  sprintf(max5, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
86 #endif
87 
88  return max5;
89 }
90 
91 /*
92 
93  New proposed interface, 9th of February 2000:
94 
95  pgrsStartNow() - sets start time
96  pgrsSetDownloadSize(x) - known expected download size
97  pgrsSetUploadSize(x) - known expected upload size
98  pgrsSetDownloadCounter() - amount of data currently downloaded
99  pgrsSetUploadCounter() - amount of data currently uploaded
100  pgrsUpdate() - show progress
101  pgrsDone() - transfer complete
102 
103 */
104 
105 void Curl_pgrsDone(struct connectdata *conn)
106 {
107  struct SessionHandle *data = conn->data;
108  if(!(data->progress.flags & PGRS_HIDE)) {
109  data->progress.lastshow=0;
110  Curl_pgrsUpdate(conn); /* the final (forced) update */
111  if(!data->progress.callback)
112  /* only output if we don't use progress callback */
113  fprintf(data->set.err, "\n");
114  }
115 }
116 
117 /* reset all times except redirect */
119 {
120  data->progress.t_nslookup = 0.0;
121  data->progress.t_connect = 0.0;
122  data->progress.t_pretransfer = 0.0;
123  data->progress.t_starttransfer = 0.0;
124 }
125 
127 {
128  switch(timer) {
129  default:
130  case TIMER_NONE:
131  /* mistake filter */
132  break;
133  case TIMER_STARTSINGLE:
134  /* This is set at the start of a single fetch */
136  break;
137 
138  case TIMER_NAMELOOKUP:
139  data->progress.t_nslookup =
140  (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
141  break;
142  case TIMER_CONNECT:
143  data->progress.t_connect =
144  (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
145  break;
146  case TIMER_PRETRANSFER:
147  data->progress.t_pretransfer =
148  (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
149  break;
150  case TIMER_STARTTRANSFER:
151  data->progress.t_starttransfer =
152  (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
153  break;
154  case TIMER_POSTRANSFER:
155  /* this is the normal end-of-transfer thing */
156  break;
157  case TIMER_REDIRECT:
158  data->progress.t_redirect =
159  (double)Curl_tvdiff(Curl_tvnow(), data->progress.start)/1000.0;
160  break;
161  }
162 }
163 
165 {
166  data->progress.speeder_c = 0; /* reset the progress meter display */
167  data->progress.start = Curl_tvnow();
168 }
169 
171 {
172  data->progress.downloaded = size;
173 }
174 
176 {
177  data->progress.uploaded = size;
178 }
179 
181 {
182  data->progress.size_dl = size;
183  if(size > 0)
185  else
187 }
188 
190 {
191  data->progress.size_ul = size;
192  if(size > 0)
194  else
196 }
197 
198 /* EXAMPLE OUTPUT to follow:
199 
200  % Total % Received % Xferd Average Speed Time Curr.
201  Dload Upload Total Current Left Speed
202 100 12345 100 12345 100 12345 12345 12345 12:12:12 12:12:12 12:12:12 12345
203 
204  */
205 
206 int Curl_pgrsUpdate(struct connectdata *conn)
207 {
208  struct timeval now;
209  int result;
210 
211  char max5[6][10];
212  double dlpercen=0;
213  double ulpercen=0;
214  double total_percen=0;
215 
216  curl_off_t total_transfer;
217  curl_off_t total_expected_transfer;
218  double timespent;
219 
220  struct SessionHandle *data = conn->data;
221 
222  int nowindex = data->progress.speeder_c% CURR_TIME;
223  int checkindex;
224 
225  int countindex; /* amount of seconds stored in the speeder array */
226 
227  char time_left[10];
228  char TIME_Total[10];
229  char time_current[10];
230 
231  double ulestimate=0;
232  double dlestimate=0;
233 
234  double total_estimate;
235 
236 
237  if(data->progress.flags & PGRS_HIDE)
238  ; /* We do enter this function even if we don't wanna see anything, since
239  this is were lots of the calculations are being made that will be used
240  even when not displayed! */
241  else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
242  if (!data->progress.callback) {
243  if(conn->resume_from)
244  fprintf(data->set.err,
245  "** Resuming transfer from byte position %" FORMAT_OFF_T
246  "\n",
247  conn->resume_from);
248  fprintf(data->set.err,
249  " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
250  " Dload Upload Total Current Left Speed\n");
251  }
252  data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
253  }
254 
255  now = Curl_tvnow(); /* what time is it */
256 
257  /* The exact time spent so far (from the start) */
258  timespent = (double)Curl_tvdiff (now, data->progress.start)/1000;
259 
260  data->progress.timespent = timespent;
261 
262  /* The average download speed this far */
263  data->progress.dlspeed =
264  (curl_off_t)( data->progress.downloaded/(timespent>0.01?timespent:1) );
265 
266  /* The average upload speed this far */
267  data->progress.ulspeed =
268  (curl_off_t)( data->progress.uploaded/(timespent>0.01?timespent:1) );
269 
270  if(data->progress.lastshow == Curl_tvlong(now))
271  return 0; /* never update this more than once a second if the end isn't
272  reached */
273  data->progress.lastshow = now.tv_sec;
274 
275  /* Let's do the "current speed" thing, which should use the fastest
276  of the dl/ul speeds. Store the fasted speed at entry 'nowindex'. */
277  data->progress.speeder[ nowindex ] =
278  data->progress.downloaded>data->progress.uploaded?
279  data->progress.downloaded:data->progress.uploaded;
280 
281  /* remember the exact time for this moment */
282  data->progress.speeder_time [ nowindex ] = now;
283 
284  /* advance our speeder_c counter, which is increased every time we get
285  here and we expect it to never wrap as 2^32 is a lot of seconds! */
286  data->progress.speeder_c++;
287 
288  /* figure out how many index entries of data we have stored in our speeder
289  array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
290  transfer. Imagine, after one second we have filled in two entries,
291  after two seconds we've filled in three entries etc. */
292  countindex = ((data->progress.speeder_c>=CURR_TIME)?
293  CURR_TIME:data->progress.speeder_c) - 1;
294 
295  /* first of all, we don't do this if there's no counted seconds yet */
296  if(countindex) {
297  long span_ms;
298 
299  /* Get the index position to compare with the 'nowindex' position.
300  Get the oldest entry possible. While we have less than CURR_TIME
301  entries, the first entry will remain the oldest. */
302  checkindex = (data->progress.speeder_c>=CURR_TIME)?
303  data->progress.speeder_c%CURR_TIME:0;
304 
305  /* Figure out the exact time for the time span */
306  span_ms = Curl_tvdiff(now,
307  data->progress.speeder_time[checkindex]);
308  if(0 == span_ms)
309  span_ms=1; /* at least one millisecond MUST have passed */
310 
311  /* Calculate the average speed the last 'countindex' seconds */
312  data->progress.current_speed =
313  (curl_off_t)((data->progress.speeder[nowindex]-
314  data->progress.speeder[checkindex])/((double)span_ms/1000) );
315  }
316  else
317  /* the first second we use the main average */
318  data->progress.current_speed =
319  (data->progress.ulspeed>data->progress.dlspeed)?
320  data->progress.ulspeed:data->progress.dlspeed;
321 
322  if(data->progress.flags & PGRS_HIDE)
323  return 0;
324 
325  else if(data->set.fprogress) {
326  /* There's a callback set, so we call that instead of writing
327  anything ourselves. This really is the way to go. */
328  result= data->set.fprogress(data->set.progress_client,
329  (double)data->progress.size_dl,
330  (double)data->progress.downloaded,
331  (double)data->progress.size_ul,
332  (double)data->progress.uploaded);
333  if(result)
334  failf(data, "Callback aborted");
335  return result;
336  }
337 
338  /* Figure out the estimated time of arrival for the upload */
339  if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
340  (data->progress.ulspeed > 0)) {
341  ulestimate = (double)data->progress.size_ul / data->progress.ulspeed;
342  ulpercen = ((double)data->progress.uploaded / data->progress.size_ul)*100;
343  }
344 
345  /* ... and the download */
346  if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
347  (data->progress.dlspeed > 0)) {
348  dlestimate = (double)data->progress.size_dl / data->progress.dlspeed;
349  dlpercen = ((double)data->progress.downloaded / data->progress.size_dl)*100;
350  }
351 
352  /* Now figure out which of them that is slower and use for the for
353  total estimate! */
354  total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
355 
356 
357  /* If we have a total estimate, we can display that and the expected
358  time left */
359  if(total_estimate > 0) {
360  time2str(time_left, (int)(total_estimate - data->progress.timespent));
361  time2str(TIME_Total, (int)total_estimate);
362  }
363  else {
364  /* otherwise we blank those times */
365  strcpy(time_left, "--:--:--");
366  strcpy(TIME_Total, "--:--:--");
367  }
368  /* The time spent so far is always known */
369  time2str(time_current, (int)data->progress.timespent);
370 
371  /* Get the total amount of data expected to get transfered */
372  total_expected_transfer =
374  data->progress.size_ul:data->progress.uploaded)+
376  data->progress.size_dl:data->progress.downloaded);
377 
378  /* We have transfered this much so far */
379  total_transfer = data->progress.downloaded + data->progress.uploaded;
380 
381  /* Get the percentage of data transfered so far */
382  if(total_expected_transfer > 0)
383  total_percen=((double)total_transfer/total_expected_transfer)*100;
384 
385  fprintf(data->set.err,
386  "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
387  (int)total_percen, /* total % */
388  max5data(total_expected_transfer, max5[2]), /* total size */
389  (int)dlpercen, /* rcvd % */
390  max5data(data->progress.downloaded, max5[0]), /* rcvd size */
391  (int)ulpercen, /* xfer % */
392  max5data(data->progress.uploaded, max5[1]), /* xfer size */
393 
394  max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
395  max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
396  TIME_Total, /* total time */
397  time_current, /* current time */
398  time_left, /* time left */
399  max5data(data->progress.current_speed, max5[5]) /* current speed */
400  );
401 
402  /* we flush the output stream to make it appear as soon as possible */
403  fflush(data->set.err);
404 
405  return 0;
406 }
struct timeval speeder_time[CURR_TIME]
Definition: urldata.h:634
void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:180
bool callback
Definition: urldata.h:614
struct timeval start
Definition: urldata.h:629
void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
Definition: progress.c:126
void Curl_pgrsDone(struct connectdata *conn)
Definition: progress.c:105
curl_off_t uploaded
Definition: urldata.h:610
long tv_sec
Definition: timeval.h:37
#define failf
Definition: sendf.h:32
#define CURR_TIME
Definition: urldata.h:631
GLdouble s
Definition: glext.h:2935
curl_off_t current_speed
Definition: urldata.h:612
off_t curl_off_t
Definition: curl.h:96
FILE * err
Definition: urldata.h:757
struct timeval t_startsingle
Definition: urldata.h:630
double t_nslookup
Definition: urldata.h:623
curl_off_t downloaded
Definition: urldata.h:609
Boolean result
struct Progress progress
Definition: urldata.h:902
void * progress_client
Definition: urldata.h:793
long Curl_tvlong(struct timeval t1)
Definition: timeval.c:98
curl_off_t resume_from
Definition: urldata.h:442
int flags
Definition: urldata.h:616
#define ONE_MEGABYTE
void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:170
int Curl_pgrsUpdate(struct connectdata *conn)
Definition: progress.c:206
void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:175
void Curl_pgrsResetTimes(struct SessionHandle *data)
Definition: progress.c:118
int speeder_c
Definition: urldata.h:635
#define FORMAT_OFF_T
Definition: setup.h:99
void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
Definition: progress.c:189
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
double t_pretransfer
Definition: urldata.h:625
double t_connect
Definition: urldata.h:624
#define ONE_GIGABYTE
long Curl_tvdiff(struct timeval newer, struct timeval older)
Definition: timeval.c:92
struct SessionHandle * data
Definition: urldata.h:403
double t_redirect
Definition: urldata.h:627
curl_progress_callback fprogress
Definition: urldata.h:791
double timespent
Definition: urldata.h:618
curl_off_t speeder[CURR_TIME]
Definition: urldata.h:633
GLdouble GLdouble GLdouble r
Definition: glext.h:2951
#define PGRS_DL_SIZE_KNOWN
Definition: progress.h:65
#define PGRS_UL_SIZE_KNOWN
Definition: progress.h:64
long lastshow
Definition: urldata.h:605
curl_off_t ulspeed
Definition: urldata.h:621
double t_starttransfer
Definition: urldata.h:626
GLsizeiptr size
Definition: glext.h:3112
curl_off_t size_ul
Definition: urldata.h:608
struct timeval Curl_tvnow(void)
Definition: timeval.c:81
#define ONE_KILOBYTE
#define PGRS_HEADERS_OUT
Definition: progress.h:67
struct UserDefined set
Definition: urldata.h:898
void Curl_pgrsStartNow(struct SessionHandle *data)
Definition: progress.c:164
timerid
Definition: progress.h:29
#define PGRS_HIDE
Definition: progress.h:63
int sprintf(idStr &string, const char *fmt,...)
Definition: Str.cpp:1528
curl_off_t dlspeed
Definition: urldata.h:620
curl_off_t size_dl
Definition: urldata.h:607
GLdouble GLdouble t
Definition: glext.h:2943