Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tag: Curl_easy_1-1-8
Fetching contributors…

Cannot retrieve contributors at this time

file 342 lines (287 sloc) 11.171 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/

#include "setup.h"

#include <string.h>

#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
#if defined(__MINGW32__)
#include <winsock.h>
#endif
#include <time.h>
#endif

/* 20000318 mgs
* later we use _scrsize to determine the screen width, this emx library
* function needs stdlib.h to be included */
#if defined(__EMX__)
#include <stdlib.h>
#endif

#include <curl/curl.h>
#include "urldata.h"
#include "sendf.h"

#include "progress.h"

static void time2str(char *r, int t)
{
  int h = (t/3600);
  int m = (t-(h*3600))/60;
  int s = (t-(h*3600)-(m*60));
  sprintf(r,"%2d:%02d:%02d",h,m,s);
}

/* The point of this function would be to return a string of the input data,
but never longer than 5 columns. Add suffix k, M, G when suitable... */
static char *max5data(double bytes, char *max5)
{
#define ONE_KILOBYTE 1024
#define ONE_MEGABYTE (1024*1024)

  if(bytes < 100000) {
    sprintf(max5, "%5d", (int)bytes);
    return max5;
  }
  if(bytes < (9999*ONE_KILOBYTE)) {
    sprintf(max5, "%4dk", (int)bytes/ONE_KILOBYTE);
    return max5;
  }
  if(bytes < (100*ONE_MEGABYTE)) {
    /* 'XX.XM' is good as long as we're less than 100 megs */
    sprintf(max5, "%2.1fM", bytes/ONE_MEGABYTE);
    return max5;
  }
  sprintf(max5, "%4dM", (int)bytes/ONE_MEGABYTE);
  return max5;
}

/*

New proposed interface, 9th of February 2000:

pgrsStartNow() - sets start time
pgrsSetDownloadSize(x) - known expected download size
pgrsSetUploadSize(x) - known expected upload size
pgrsSetDownloadCounter() - amount of data currently downloaded
pgrsSetUploadCounter() - amount of data currently uploaded
pgrsUpdate() - show progress
pgrsDone() - transfer complete

*/

void Curl_pgrsDone(struct connectdata *conn)
{
  struct SessionHandle *data = conn->data;
  if(!(data->progress.flags & PGRS_HIDE)) {
    data->progress.lastshow=0;
    Curl_pgrsUpdate(conn); /* the final (forced) update */
    if(!data->progress.callback)
      /* only output if we don't use progress callback */
      fprintf(data->set.err, "\n");
  }
}

void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
{
  switch(timer) {
  default:
  case TIMER_NONE:
    /* mistake filter */
    break;
  case TIMER_STARTSINGLE:
    /* This is set at the start of a single fetch, there may be several
fetches within an operation, why we add all other times relative
to this one */
    data->progress.t_startsingle = Curl_tvnow();
    break;

  case TIMER_NAMELOOKUP:
    data->progress.t_nslookup += Curl_tvdiff(Curl_tvnow(),
                                        data->progress.t_startsingle);
    break;
  case TIMER_CONNECT:
    data->progress.t_connect += Curl_tvdiff(Curl_tvnow(),
                                       data->progress.t_startsingle);
    break;
  case TIMER_PRETRANSFER:
    data->progress.t_pretransfer += Curl_tvdiff(Curl_tvnow(),
                                           data->progress.t_startsingle);
    break;
  case TIMER_POSTRANSFER:
    /* this is the normal end-of-transfer thing */
    break;
  }
}

void Curl_pgrsStartNow(struct SessionHandle *data)
{
  data->progress.speeder_c = 0; /* reset the progress meter display */
  data->progress.start = Curl_tvnow();
}

void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, double size)
{
  data->progress.downloaded = size;
}

void Curl_pgrsSetUploadCounter(struct SessionHandle *data, double size)
{
  data->progress.uploaded = size;
}

void Curl_pgrsSetDownloadSize(struct SessionHandle *data, double size)
{
  if(size > 0) {
    data->progress.size_dl = size;
    data->progress.flags |= PGRS_DL_SIZE_KNOWN;
  }
}

void Curl_pgrsSetUploadSize(struct SessionHandle *data, double size)
{
  if(size > 0) {
    data->progress.size_ul = size;
    data->progress.flags |= PGRS_UL_SIZE_KNOWN;
  }
}

/* EXAMPLE OUTPUT to follow:

% Total % Received % Xferd Average Speed Time Curr.
Dload Upload Total Current Left Speed
100 12345 100 12345 100 12345 12345 12345 12:12:12 12:12:12 12:12:12 12345

*/

int Curl_pgrsUpdate(struct connectdata *conn)
{
  struct timeval now;
  int result;

  char max5[6][10];
  double dlpercen=0;
  double ulpercen=0;
  double total_percen=0;

  double total_transfer;
  double total_expected_transfer;

  struct SessionHandle *data = conn->data;

  int nowindex = data->progress.speeder_c% CURR_TIME;
  int checkindex;
  int count;

  char time_left[10];
  char time_total[10];
  char time_current[10];
      
  double ulestimate=0;
  double dlestimate=0;
  
  double total_estimate;


  if(data->progress.flags & PGRS_HIDE)
    ; /* We do enter this function even if we don't wanna see anything, since
this is were lots of the calculations are being made that will be used
even when not displayed! */
  else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
    if (!data->progress.callback) {
      if(conn->resume_from)
        fprintf(data->set.err, "** Resuming transfer from byte position %d\n",
                conn->resume_from);
      fprintf(data->set.err,
              " %% Total %% Received %% Xferd Average Speed Time Curr.\n"
              " Dload Upload Total Current Left Speed\n");
    }
    data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
  }

  now = Curl_tvnow(); /* what time is it */

  /* The exact time spent so far */
  data->progress.timespent = Curl_tvdiff (now, data->progress.start);

  /* The average download speed this far */
  data->progress.dlspeed = data->progress.downloaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);

  /* The average upload speed this far */
  data->progress.ulspeed = data->progress.uploaded/(data->progress.timespent!=0.0?data->progress.timespent:1.0);

  if(data->progress.lastshow == Curl_tvlong(now))
    return 0; /* never update this more than once a second if the end isn't
reached */
  data->progress.lastshow = now.tv_sec;

  /* Let's do the "current speed" thing, which should use the fastest
of the dl/ul speeds */
  data->progress.speeder[ nowindex ] =
    data->progress.downloaded>data->progress.uploaded?
    data->progress.downloaded:data->progress.uploaded;
  data->progress.speeder_c++; /* increase */
  count = ((data->progress.speeder_c>=CURR_TIME)?
           CURR_TIME:data->progress.speeder_c) - 1;
  checkindex = (data->progress.speeder_c>=CURR_TIME)?
    data->progress.speeder_c%CURR_TIME:0;

  /* find out the average speed the last CURR_TIME seconds */
  data->progress.current_speed =
    (data->progress.speeder[nowindex]-
     data->progress.speeder[checkindex])/(count?count:1);

  if(data->progress.flags & PGRS_HIDE)
    return 0;
  else if(data->set.fprogress) {
    result= data->set.fprogress(data->set.progress_client,
                                data->progress.size_dl,
                                data->progress.downloaded,
                                data->progress.size_ul,
                                data->progress.uploaded);
    if(result)
      failf(data, "Callback aborted");
    return result;
  }

      /* Figure out the estimated time of arrival for the upload */
  if((data->progress.flags & PGRS_UL_SIZE_KNOWN) && data->progress.ulspeed){
    ulestimate = data->progress.size_ul / data->progress.ulspeed;
    ulpercen = (data->progress.uploaded / data->progress.size_ul)*100;
  }

  /* ... and the download */
  if((data->progress.flags & PGRS_DL_SIZE_KNOWN) && data->progress.dlspeed) {
    dlestimate = data->progress.size_dl / data->progress.dlspeed;
    dlpercen = (data->progress.downloaded / data->progress.size_dl)*100;
  }
    
  /* Now figure out which of them that is slower and use for the for
total estimate! */
  total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;


  /* If we have a total estimate, we can display that and the expected
time left */
  if(total_estimate) {
    time2str(time_left, total_estimate-(int) data->progress.timespent);
    time2str(time_total, total_estimate);
  }
  else {
    /* otherwise we blank those times */
    strcpy(time_left, "--:--:--");
    strcpy(time_total, "--:--:--");
  }
  /* The time spent so far is always known */
  time2str(time_current, data->progress.timespent);

  /* Get the total amount of data expected to get transfered */
  total_expected_transfer =
    (data->progress.flags & PGRS_UL_SIZE_KNOWN?
     data->progress.size_ul:data->progress.uploaded)+
    (data->progress.flags & PGRS_DL_SIZE_KNOWN?
     data->progress.size_dl:data->progress.downloaded);
      
  /* We have transfered this much so far */
  total_transfer = data->progress.downloaded + data->progress.uploaded;

  /* Get the percentage of data transfered so far */
  if(total_expected_transfer)
    total_percen=(double)(total_transfer/total_expected_transfer)*100;

  fprintf(data->set.err,
          "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
          (int)total_percen, /* total % */
          max5data(total_expected_transfer, max5[2]), /* total size */
          (int)dlpercen, /* rcvd % */
          max5data(data->progress.downloaded, max5[0]), /* rcvd size */
          (int)ulpercen, /* xfer % */
          max5data(data->progress.uploaded, max5[1]), /* xfer size */

          max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
          max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
          time_total, /* total time */
          time_current, /* current time */
          time_left, /* time left */
          max5data(data->progress.current_speed, max5[5]) /* current speed */
          );

  /* we flush the output stream to make it appear as soon as possible */
  fflush(data->set.err);

  return 0;
}

/*
* local variables:
* eval: (load-file "../curl-mode.el")
* end:
* vim600: et sw=2 ts=2 sts=2 tw=78 fdm=marker
* vim<600: et sw=2 ts=2 sts=2 tw=78
*/
Something went wrong with that request. Please try again.