113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci#include "tool_setup.h" 2513498266Sopenharmony_ci 2613498266Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 2713498266Sopenharmony_ci#include <sys/ioctl.h> 2813498266Sopenharmony_ci#endif 2913498266Sopenharmony_ci 3013498266Sopenharmony_ci#define ENABLE_CURLX_PRINTF 3113498266Sopenharmony_ci/* use our own printf() functions */ 3213498266Sopenharmony_ci#include "curlx.h" 3313498266Sopenharmony_ci 3413498266Sopenharmony_ci#include "tool_cfgable.h" 3513498266Sopenharmony_ci#include "tool_cb_prg.h" 3613498266Sopenharmony_ci#include "tool_util.h" 3713498266Sopenharmony_ci#include "tool_operate.h" 3813498266Sopenharmony_ci 3913498266Sopenharmony_ci#include "memdebug.h" /* keep this as LAST include */ 4013498266Sopenharmony_ci 4113498266Sopenharmony_ci#define MAX_BARLENGTH 256 4213498266Sopenharmony_ci 4313498266Sopenharmony_ci#ifdef HAVE_TERMIOS_H 4413498266Sopenharmony_ci# include <termios.h> 4513498266Sopenharmony_ci#elif defined(HAVE_TERMIO_H) 4613498266Sopenharmony_ci# include <termio.h> 4713498266Sopenharmony_ci#endif 4813498266Sopenharmony_ci 4913498266Sopenharmony_ci/* 200 values generated by this perl code: 5013498266Sopenharmony_ci 5113498266Sopenharmony_ci my $pi = 3.1415; 5213498266Sopenharmony_ci foreach my $i (1 .. 200) { 5313498266Sopenharmony_ci printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000; 5413498266Sopenharmony_ci } 5513498266Sopenharmony_ci*/ 5613498266Sopenharmony_cistatic const unsigned int sinus[] = { 5713498266Sopenharmony_ci 515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491, 5813498266Sopenharmony_ci 654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906, 5913498266Sopenharmony_ci 781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047, 6013498266Sopenharmony_ci 885248, 895069, 904500, 913532, 922156, 930363, 938145, 945495, 952406, 6113498266Sopenharmony_ci 958870, 964881, 970434, 975522, 980141, 984286, 987954, 991139, 993840, 6213498266Sopenharmony_ci 996054, 997778, 999011, 999752, 999999, 999754, 999014, 997783, 996060, 6313498266Sopenharmony_ci 993848, 991148, 987964, 984298, 980154, 975536, 970449, 964898, 958888, 6413498266Sopenharmony_ci 952426, 945516, 938168, 930386, 922180, 913558, 904527, 895097, 885277, 6513498266Sopenharmony_ci 875077, 864507, 853577, 842299, 830682, 818739, 806482, 793922, 781072, 6613498266Sopenharmony_ci 767945, 754553, 740910, 727030, 712925, 698610, 684100, 669407, 654548, 6713498266Sopenharmony_ci 639536, 624386, 609113, 593733, 578260, 562710, 547098, 531440, 515751, 6813498266Sopenharmony_ci 500046, 484341, 468651, 452993, 437381, 421830, 406357, 390976, 375703, 6913498266Sopenharmony_ci 360552, 345539, 330679, 315985, 301474, 287158, 273052, 259170, 245525, 7013498266Sopenharmony_ci 232132, 219003, 206152, 193590, 181331, 169386, 157768, 146487, 135555, 7113498266Sopenharmony_ci 124983, 114781, 104959, 95526, 86493, 77868, 69660, 61876, 54525, 47613, 7213498266Sopenharmony_ci 41147, 35135, 29581, 24491, 19871, 15724, 12056, 8868, 6166, 3951, 2225, 7313498266Sopenharmony_ci 990, 248, 0, 244, 982, 2212, 3933, 6144, 8842, 12025, 15690, 19832, 24448, 7413498266Sopenharmony_ci 29534, 35084, 41092, 47554, 54462, 61809, 69589, 77794, 86415, 95445, 7513498266Sopenharmony_ci 104873, 114692, 124891, 135460, 146389, 157667, 169282, 181224, 193480, 7613498266Sopenharmony_ci 206039, 218888, 232015, 245406, 259048, 272928, 287032, 301346, 315856, 7713498266Sopenharmony_ci 330548, 345407, 360419, 375568, 390841, 406221, 421693, 437243, 452854, 7813498266Sopenharmony_ci 468513, 484202, 499907 7913498266Sopenharmony_ci}; 8013498266Sopenharmony_ci 8113498266Sopenharmony_cistatic void fly(struct ProgressData *bar, bool moved) 8213498266Sopenharmony_ci{ 8313498266Sopenharmony_ci char buf[MAX_BARLENGTH + 2]; 8413498266Sopenharmony_ci int pos; 8513498266Sopenharmony_ci int check = bar->width - 2; 8613498266Sopenharmony_ci 8713498266Sopenharmony_ci /* bar->width is range checked when assigned */ 8813498266Sopenharmony_ci DEBUGASSERT(bar->width <= MAX_BARLENGTH); 8913498266Sopenharmony_ci memset(buf, ' ', bar->width); 9013498266Sopenharmony_ci buf[bar->width] = '\r'; 9113498266Sopenharmony_ci buf[bar->width + 1] = '\0'; 9213498266Sopenharmony_ci 9313498266Sopenharmony_ci memcpy(&buf[bar->bar], "-=O=-", 5); 9413498266Sopenharmony_ci 9513498266Sopenharmony_ci pos = sinus[bar->tick%200] / (1000000 / check); 9613498266Sopenharmony_ci buf[pos] = '#'; 9713498266Sopenharmony_ci pos = sinus[(bar->tick + 5)%200] / (1000000 / check); 9813498266Sopenharmony_ci buf[pos] = '#'; 9913498266Sopenharmony_ci pos = sinus[(bar->tick + 10)%200] / (1000000 / check); 10013498266Sopenharmony_ci buf[pos] = '#'; 10113498266Sopenharmony_ci pos = sinus[(bar->tick + 15)%200] / (1000000 / check); 10213498266Sopenharmony_ci buf[pos] = '#'; 10313498266Sopenharmony_ci 10413498266Sopenharmony_ci fputs(buf, bar->out); 10513498266Sopenharmony_ci bar->tick += 2; 10613498266Sopenharmony_ci if(bar->tick >= 200) 10713498266Sopenharmony_ci bar->tick -= 200; 10813498266Sopenharmony_ci 10913498266Sopenharmony_ci bar->bar += (moved?bar->barmove:0); 11013498266Sopenharmony_ci if(bar->bar >= (bar->width - 6)) { 11113498266Sopenharmony_ci bar->barmove = -1; 11213498266Sopenharmony_ci bar->bar = bar->width - 6; 11313498266Sopenharmony_ci } 11413498266Sopenharmony_ci else if(bar->bar < 0) { 11513498266Sopenharmony_ci bar->barmove = 1; 11613498266Sopenharmony_ci bar->bar = 0; 11713498266Sopenharmony_ci } 11813498266Sopenharmony_ci} 11913498266Sopenharmony_ci 12013498266Sopenharmony_ci/* 12113498266Sopenharmony_ci** callback for CURLOPT_XFERINFOFUNCTION 12213498266Sopenharmony_ci*/ 12313498266Sopenharmony_ci 12413498266Sopenharmony_ci#if (SIZEOF_CURL_OFF_T < 8) 12513498266Sopenharmony_ci#error "too small curl_off_t" 12613498266Sopenharmony_ci#else 12713498266Sopenharmony_ci /* assume SIZEOF_CURL_OFF_T == 8 */ 12813498266Sopenharmony_ci# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) 12913498266Sopenharmony_ci#endif 13013498266Sopenharmony_ci 13113498266Sopenharmony_ciint tool_progress_cb(void *clientp, 13213498266Sopenharmony_ci curl_off_t dltotal, curl_off_t dlnow, 13313498266Sopenharmony_ci curl_off_t ultotal, curl_off_t ulnow) 13413498266Sopenharmony_ci{ 13513498266Sopenharmony_ci struct timeval now = tvnow(); 13613498266Sopenharmony_ci struct per_transfer *per = clientp; 13713498266Sopenharmony_ci struct OperationConfig *config = per->config; 13813498266Sopenharmony_ci struct ProgressData *bar = &per->progressbar; 13913498266Sopenharmony_ci curl_off_t total; 14013498266Sopenharmony_ci curl_off_t point; 14113498266Sopenharmony_ci 14213498266Sopenharmony_ci /* Calculate expected transfer size. initial_size can be less than zero when 14313498266Sopenharmony_ci indicating that we are expecting to get the filesize from the remote */ 14413498266Sopenharmony_ci if(bar->initial_size < 0) { 14513498266Sopenharmony_ci if(dltotal || ultotal) 14613498266Sopenharmony_ci total = dltotal + ultotal; 14713498266Sopenharmony_ci else 14813498266Sopenharmony_ci total = CURL_OFF_T_MAX; 14913498266Sopenharmony_ci } 15013498266Sopenharmony_ci else if((CURL_OFF_T_MAX - bar->initial_size) < (dltotal + ultotal)) 15113498266Sopenharmony_ci total = CURL_OFF_T_MAX; 15213498266Sopenharmony_ci else 15313498266Sopenharmony_ci total = dltotal + ultotal + bar->initial_size; 15413498266Sopenharmony_ci 15513498266Sopenharmony_ci /* Calculate the current progress. initial_size can be less than zero when 15613498266Sopenharmony_ci indicating that we are expecting to get the filesize from the remote */ 15713498266Sopenharmony_ci if(bar->initial_size < 0) { 15813498266Sopenharmony_ci if(dltotal || ultotal) 15913498266Sopenharmony_ci point = dlnow + ulnow; 16013498266Sopenharmony_ci else 16113498266Sopenharmony_ci point = CURL_OFF_T_MAX; 16213498266Sopenharmony_ci } 16313498266Sopenharmony_ci else if((CURL_OFF_T_MAX - bar->initial_size) < (dlnow + ulnow)) 16413498266Sopenharmony_ci point = CURL_OFF_T_MAX; 16513498266Sopenharmony_ci else 16613498266Sopenharmony_ci point = dlnow + ulnow + bar->initial_size; 16713498266Sopenharmony_ci 16813498266Sopenharmony_ci if(bar->calls) { 16913498266Sopenharmony_ci /* after first call... */ 17013498266Sopenharmony_ci if(total) { 17113498266Sopenharmony_ci /* we know the total data to get... */ 17213498266Sopenharmony_ci if(bar->prev == point) 17313498266Sopenharmony_ci /* progress didn't change since last invoke */ 17413498266Sopenharmony_ci return 0; 17513498266Sopenharmony_ci else if((tvdiff(now, bar->prevtime) < 100L) && point < total) 17613498266Sopenharmony_ci /* limit progress-bar updating to 10 Hz except when we're at 100% */ 17713498266Sopenharmony_ci return 0; 17813498266Sopenharmony_ci } 17913498266Sopenharmony_ci else { 18013498266Sopenharmony_ci /* total is unknown */ 18113498266Sopenharmony_ci if(tvdiff(now, bar->prevtime) < 100L) 18213498266Sopenharmony_ci /* limit progress-bar updating to 10 Hz */ 18313498266Sopenharmony_ci return 0; 18413498266Sopenharmony_ci fly(bar, point != bar->prev); 18513498266Sopenharmony_ci } 18613498266Sopenharmony_ci } 18713498266Sopenharmony_ci 18813498266Sopenharmony_ci /* simply count invokes */ 18913498266Sopenharmony_ci bar->calls++; 19013498266Sopenharmony_ci 19113498266Sopenharmony_ci if((total > 0) && (point != bar->prev)) { 19213498266Sopenharmony_ci char line[MAX_BARLENGTH + 1]; 19313498266Sopenharmony_ci char format[40]; 19413498266Sopenharmony_ci double frac; 19513498266Sopenharmony_ci double percent; 19613498266Sopenharmony_ci int barwidth; 19713498266Sopenharmony_ci int num; 19813498266Sopenharmony_ci if(point > total) 19913498266Sopenharmony_ci /* we have got more than the expected total! */ 20013498266Sopenharmony_ci total = point; 20113498266Sopenharmony_ci 20213498266Sopenharmony_ci frac = (double)point / (double)total; 20313498266Sopenharmony_ci percent = frac * 100.0; 20413498266Sopenharmony_ci barwidth = bar->width - 7; 20513498266Sopenharmony_ci num = (int) (((double)barwidth) * frac); 20613498266Sopenharmony_ci if(num > MAX_BARLENGTH) 20713498266Sopenharmony_ci num = MAX_BARLENGTH; 20813498266Sopenharmony_ci memset(line, '#', num); 20913498266Sopenharmony_ci line[num] = '\0'; 21013498266Sopenharmony_ci msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth); 21113498266Sopenharmony_ci#ifdef __clang__ 21213498266Sopenharmony_ci#pragma clang diagnostic push 21313498266Sopenharmony_ci#pragma clang diagnostic ignored "-Wformat-nonliteral" 21413498266Sopenharmony_ci#endif 21513498266Sopenharmony_ci fprintf(bar->out, format, line, percent); 21613498266Sopenharmony_ci#ifdef __clang__ 21713498266Sopenharmony_ci#pragma clang diagnostic pop 21813498266Sopenharmony_ci#endif 21913498266Sopenharmony_ci } 22013498266Sopenharmony_ci fflush(bar->out); 22113498266Sopenharmony_ci bar->prev = point; 22213498266Sopenharmony_ci bar->prevtime = now; 22313498266Sopenharmony_ci 22413498266Sopenharmony_ci if(config->readbusy) { 22513498266Sopenharmony_ci config->readbusy = FALSE; 22613498266Sopenharmony_ci curl_easy_pause(per->curl, CURLPAUSE_CONT); 22713498266Sopenharmony_ci } 22813498266Sopenharmony_ci 22913498266Sopenharmony_ci return 0; 23013498266Sopenharmony_ci} 23113498266Sopenharmony_ci 23213498266Sopenharmony_civoid progressbarinit(struct ProgressData *bar, 23313498266Sopenharmony_ci struct OperationConfig *config) 23413498266Sopenharmony_ci{ 23513498266Sopenharmony_ci char *colp; 23613498266Sopenharmony_ci memset(bar, 0, sizeof(struct ProgressData)); 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci /* pass the resume from value through to the progress function so it can 23913498266Sopenharmony_ci * display progress towards total file not just the part that's left. */ 24013498266Sopenharmony_ci if(config->use_resume) 24113498266Sopenharmony_ci bar->initial_size = config->resume_from; 24213498266Sopenharmony_ci 24313498266Sopenharmony_ci colp = curlx_getenv("COLUMNS"); 24413498266Sopenharmony_ci if(colp) { 24513498266Sopenharmony_ci char *endptr; 24613498266Sopenharmony_ci long num = strtol(colp, &endptr, 10); 24713498266Sopenharmony_ci if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) && 24813498266Sopenharmony_ci (num < 10000)) 24913498266Sopenharmony_ci bar->width = (int)num; 25013498266Sopenharmony_ci curl_free(colp); 25113498266Sopenharmony_ci } 25213498266Sopenharmony_ci 25313498266Sopenharmony_ci if(!bar->width) { 25413498266Sopenharmony_ci int cols = 0; 25513498266Sopenharmony_ci 25613498266Sopenharmony_ci#ifdef TIOCGSIZE 25713498266Sopenharmony_ci struct ttysize ts; 25813498266Sopenharmony_ci if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts)) 25913498266Sopenharmony_ci cols = ts.ts_cols; 26013498266Sopenharmony_ci#elif defined(TIOCGWINSZ) 26113498266Sopenharmony_ci struct winsize ts; 26213498266Sopenharmony_ci if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts)) 26313498266Sopenharmony_ci cols = ts.ws_col; 26413498266Sopenharmony_ci#elif defined(_WIN32) 26513498266Sopenharmony_ci { 26613498266Sopenharmony_ci HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE); 26713498266Sopenharmony_ci CONSOLE_SCREEN_BUFFER_INFO console_info; 26813498266Sopenharmony_ci 26913498266Sopenharmony_ci if((stderr_hnd != INVALID_HANDLE_VALUE) && 27013498266Sopenharmony_ci GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) { 27113498266Sopenharmony_ci /* 27213498266Sopenharmony_ci * Do not use +1 to get the true screen-width since writing a 27313498266Sopenharmony_ci * character at the right edge will cause a line wrap. 27413498266Sopenharmony_ci */ 27513498266Sopenharmony_ci cols = (int) 27613498266Sopenharmony_ci (console_info.srWindow.Right - console_info.srWindow.Left); 27713498266Sopenharmony_ci } 27813498266Sopenharmony_ci } 27913498266Sopenharmony_ci#endif /* TIOCGSIZE */ 28013498266Sopenharmony_ci if(cols > 20) 28113498266Sopenharmony_ci bar->width = cols; 28213498266Sopenharmony_ci } 28313498266Sopenharmony_ci 28413498266Sopenharmony_ci if(!bar->width) 28513498266Sopenharmony_ci bar->width = 79; 28613498266Sopenharmony_ci else if(bar->width > MAX_BARLENGTH) 28713498266Sopenharmony_ci bar->width = MAX_BARLENGTH; 28813498266Sopenharmony_ci 28913498266Sopenharmony_ci bar->out = tool_stderr; 29013498266Sopenharmony_ci bar->tick = 150; 29113498266Sopenharmony_ci bar->barmove = 1; 29213498266Sopenharmony_ci} 293