summaryrefslogtreecommitdiffstats
path: root/Source/CTest/Curl/progress.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/CTest/Curl/progress.c')
-rw-r--r--Source/CTest/Curl/progress.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/Source/CTest/Curl/progress.c b/Source/CTest/Curl/progress.c
new file mode 100644
index 0000000..318a6d8
--- /dev/null
+++ b/Source/CTest/Curl/progress.c
@@ -0,0 +1,384 @@
+/*****************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2001, 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, "%4.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 */
+ data->progress.t_startsingle = Curl_tvnow();
+ break;
+
+ case TIMER_NAMELOOKUP:
+ data->progress.t_nslookup =
+ (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ break;
+ case TIMER_CONNECT:
+ data->progress.t_connect =
+ (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ break;
+ case TIMER_PRETRANSFER:
+ data->progress.t_pretransfer =
+ (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ break;
+ case TIMER_STARTTRANSFER:
+ data->progress.t_starttransfer =
+ (double)Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle)/1000.0;
+ 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;
+ double timespent;
+
+ struct SessionHandle *data = conn->data;
+
+ int nowindex = data->progress.speeder_c% CURR_TIME;
+ int checkindex;
+
+ int countindex; /* amount of seconds stored in the speeder array */
+
+ 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 (from the start) */
+ timespent = (double)Curl_tvdiff (now, data->progress.start)/1000;
+
+ data->progress.timespent = timespent;
+
+ /* The average download speed this far */
+ data->progress.dlspeed =
+ data->progress.downloaded/(timespent>0.01?timespent:1);
+
+ /* The average upload speed this far */
+ data->progress.ulspeed =
+ data->progress.uploaded/(timespent>0.01?timespent:1);
+
+ 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. Store the fasted speed at entry 'nowindex'. */
+ data->progress.speeder[ nowindex ] =
+ data->progress.downloaded>data->progress.uploaded?
+ data->progress.downloaded:data->progress.uploaded;
+
+ /* remember the exact time for this moment */
+ data->progress.speeder_time [ nowindex ] = now;
+
+ /* advance our speeder_c counter, which is increased every time we get
+ here and we expect it to never wrap as 2^32 is a lot of seconds! */
+ data->progress.speeder_c++;
+
+ /* figure out how many index entries of data we have stored in our speeder
+ array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
+ transfer. Imagine, after one second we have filled in two entries,
+ after two seconds we've filled in three entries etc. */
+ countindex = ((data->progress.speeder_c>=CURR_TIME)?
+ CURR_TIME:data->progress.speeder_c) - 1;
+
+ /* first of all, we don't do this if there's no counted seconds yet */
+ if(countindex) {
+ long span_ms;
+
+ /* Get the index position to compare with the 'nowindex' position.
+ Get the oldest entry possible. While we have less than CURR_TIME
+ entries, the first entry will remain the oldest. */
+ checkindex = (data->progress.speeder_c>=CURR_TIME)?
+ data->progress.speeder_c%CURR_TIME:0;
+
+ /* Figure out the exact time for the time span */
+ span_ms = Curl_tvdiff(now,
+ data->progress.speeder_time[checkindex]);
+ if(0 == span_ms)
+ span_ms=1; /* at least one millisecond MUST have passed */
+
+ /* Calculate the average speed the last 'countindex' seconds */
+ data->progress.current_speed =
+ (data->progress.speeder[nowindex]-
+ data->progress.speeder[checkindex])/((double)span_ms/1000);
+ }
+ else
+ /* the first second we use the main average */
+ data->progress.current_speed =
+ (data->progress.ulspeed>data->progress.dlspeed)?
+ data->progress.ulspeed:data->progress.dlspeed;
+
+ if(data->progress.flags & PGRS_HIDE)
+ return 0;
+
+ else if(data->set.fprogress) {
+ /* There's a callback set, so we call that instead of writing
+ anything ourselves. This really is the way to go. */
+ 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: fdm=marker
+ * vim: et sw=2 ts=2 sts=2 tw=78
+ */