tool_cb_prg.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) 1998 - 2022, 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 https://curl.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. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "tool_setup.h"
  25. #ifdef HAVE_SYS_IOCTL_H
  26. #include <sys/ioctl.h>
  27. #endif
  28. #define ENABLE_CURLX_PRINTF
  29. /* use our own printf() functions */
  30. #include "curlx.h"
  31. #include "tool_cfgable.h"
  32. #include "tool_cb_prg.h"
  33. #include "tool_util.h"
  34. #include "tool_operate.h"
  35. #include "memdebug.h" /* keep this as LAST include */
  36. #ifdef HAVE_TERMIOS_H
  37. # include <termios.h>
  38. #elif defined(HAVE_TERMIO_H)
  39. # include <termio.h>
  40. #endif
  41. /* 200 values generated by this perl code:
  42. my $pi = 3.1415;
  43. foreach my $i (1 .. 200) {
  44. printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000;
  45. }
  46. */
  47. static const unsigned int sinus[] = {
  48. 515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491,
  49. 654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906,
  50. 781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047,
  51. 885248, 895069, 904500, 913532, 922156, 930363, 938145, 945495, 952406,
  52. 958870, 964881, 970434, 975522, 980141, 984286, 987954, 991139, 993840,
  53. 996054, 997778, 999011, 999752, 999999, 999754, 999014, 997783, 996060,
  54. 993848, 991148, 987964, 984298, 980154, 975536, 970449, 964898, 958888,
  55. 952426, 945516, 938168, 930386, 922180, 913558, 904527, 895097, 885277,
  56. 875077, 864507, 853577, 842299, 830682, 818739, 806482, 793922, 781072,
  57. 767945, 754553, 740910, 727030, 712925, 698610, 684100, 669407, 654548,
  58. 639536, 624386, 609113, 593733, 578260, 562710, 547098, 531440, 515751,
  59. 500046, 484341, 468651, 452993, 437381, 421830, 406357, 390976, 375703,
  60. 360552, 345539, 330679, 315985, 301474, 287158, 273052, 259170, 245525,
  61. 232132, 219003, 206152, 193590, 181331, 169386, 157768, 146487, 135555,
  62. 124983, 114781, 104959, 95526, 86493, 77868, 69660, 61876, 54525, 47613,
  63. 41147, 35135, 29581, 24491, 19871, 15724, 12056, 8868, 6166, 3951, 2225,
  64. 990, 248, 0, 244, 982, 2212, 3933, 6144, 8842, 12025, 15690, 19832, 24448,
  65. 29534, 35084, 41092, 47554, 54462, 61809, 69589, 77794, 86415, 95445,
  66. 104873, 114692, 124891, 135460, 146389, 157667, 169282, 181224, 193480,
  67. 206039, 218888, 232015, 245406, 259048, 272928, 287032, 301346, 315856,
  68. 330548, 345407, 360419, 375568, 390841, 406221, 421693, 437243, 452854,
  69. 468513, 484202, 499907
  70. };
  71. static void fly(struct ProgressData *bar, bool moved)
  72. {
  73. char buf[256];
  74. int pos;
  75. int check = bar->width - 2;
  76. msnprintf(buf, sizeof(buf), "%*s\r", bar->width-1, " ");
  77. memcpy(&buf[bar->bar], "-=O=-", 5);
  78. pos = sinus[bar->tick%200] / (1000000 / check);
  79. buf[pos] = '#';
  80. pos = sinus[(bar->tick + 5)%200] / (1000000 / check);
  81. buf[pos] = '#';
  82. pos = sinus[(bar->tick + 10)%200] / (1000000 / check);
  83. buf[pos] = '#';
  84. pos = sinus[(bar->tick + 15)%200] / (1000000 / check);
  85. buf[pos] = '#';
  86. fputs(buf, bar->out);
  87. bar->tick += 2;
  88. if(bar->tick >= 200)
  89. bar->tick -= 200;
  90. bar->bar += (moved?bar->barmove:0);
  91. if(bar->bar >= (bar->width - 6)) {
  92. bar->barmove = -1;
  93. bar->bar = bar->width - 6;
  94. }
  95. else if(bar->bar < 0) {
  96. bar->barmove = 1;
  97. bar->bar = 0;
  98. }
  99. }
  100. /*
  101. ** callback for CURLOPT_XFERINFOFUNCTION
  102. */
  103. #define MAX_BARLENGTH 256
  104. #if (SIZEOF_CURL_OFF_T == 4)
  105. # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
  106. #else
  107. /* assume SIZEOF_CURL_OFF_T == 8 */
  108. # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
  109. #endif
  110. int tool_progress_cb(void *clientp,
  111. curl_off_t dltotal, curl_off_t dlnow,
  112. curl_off_t ultotal, curl_off_t ulnow)
  113. {
  114. struct timeval now = tvnow();
  115. struct per_transfer *per = clientp;
  116. struct OperationConfig *config = per->config;
  117. struct ProgressData *bar = &per->progressbar;
  118. curl_off_t total;
  119. curl_off_t point;
  120. /* Calculate expected transfer size. initial_size can be less than zero when
  121. indicating that we are expecting to get the filesize from the remote */
  122. if(bar->initial_size < 0) {
  123. if(dltotal || ultotal)
  124. total = dltotal + ultotal;
  125. else
  126. total = CURL_OFF_T_MAX;
  127. }
  128. else if((CURL_OFF_T_MAX - bar->initial_size) < (dltotal + ultotal))
  129. total = CURL_OFF_T_MAX;
  130. else
  131. total = dltotal + ultotal + bar->initial_size;
  132. /* Calculate the current progress. initial_size can be less than zero when
  133. indicating that we are expecting to get the filesize from the remote */
  134. if(bar->initial_size < 0) {
  135. if(dltotal || ultotal)
  136. point = dlnow + ulnow;
  137. else
  138. point = CURL_OFF_T_MAX;
  139. }
  140. else if((CURL_OFF_T_MAX - bar->initial_size) < (dlnow + ulnow))
  141. point = CURL_OFF_T_MAX;
  142. else
  143. point = dlnow + ulnow + bar->initial_size;
  144. if(bar->calls) {
  145. /* after first call... */
  146. if(total) {
  147. /* we know the total data to get... */
  148. if(bar->prev == point)
  149. /* progress didn't change since last invoke */
  150. return 0;
  151. else if((tvdiff(now, bar->prevtime) < 100L) && point < total)
  152. /* limit progress-bar updating to 10 Hz except when we're at 100% */
  153. return 0;
  154. }
  155. else {
  156. /* total is unknown */
  157. if(tvdiff(now, bar->prevtime) < 100L)
  158. /* limit progress-bar updating to 10 Hz */
  159. return 0;
  160. fly(bar, point != bar->prev);
  161. }
  162. }
  163. /* simply count invokes */
  164. bar->calls++;
  165. if((total > 0) && (point != bar->prev)) {
  166. char line[MAX_BARLENGTH + 1];
  167. char format[40];
  168. double frac;
  169. double percent;
  170. int barwidth;
  171. int num;
  172. if(point > total)
  173. /* we have got more than the expected total! */
  174. total = point;
  175. frac = (double)point / (double)total;
  176. percent = frac * 100.0;
  177. barwidth = bar->width - 7;
  178. num = (int) (((double)barwidth) * frac);
  179. if(num > MAX_BARLENGTH)
  180. num = MAX_BARLENGTH;
  181. memset(line, '#', num);
  182. line[num] = '\0';
  183. msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth);
  184. fprintf(bar->out, format, line, percent);
  185. }
  186. fflush(bar->out);
  187. bar->prev = point;
  188. bar->prevtime = now;
  189. if(config->readbusy) {
  190. config->readbusy = FALSE;
  191. curl_easy_pause(per->curl, CURLPAUSE_CONT);
  192. }
  193. return 0;
  194. }
  195. void progressbarinit(struct ProgressData *bar,
  196. struct OperationConfig *config)
  197. {
  198. char *colp;
  199. memset(bar, 0, sizeof(struct ProgressData));
  200. /* pass the resume from value through to the progress function so it can
  201. * display progress towards total file not just the part that's left. */
  202. if(config->use_resume)
  203. bar->initial_size = config->resume_from;
  204. colp = curlx_getenv("COLUMNS");
  205. if(colp) {
  206. char *endptr;
  207. long num = strtol(colp, &endptr, 10);
  208. if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) &&
  209. (num < 10000))
  210. bar->width = (int)num;
  211. curl_free(colp);
  212. }
  213. if(!bar->width) {
  214. int cols = 0;
  215. #ifdef TIOCGSIZE
  216. struct ttysize ts;
  217. if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts))
  218. cols = ts.ts_cols;
  219. #elif defined(TIOCGWINSZ)
  220. struct winsize ts;
  221. if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts))
  222. cols = ts.ws_col;
  223. #elif defined(WIN32)
  224. {
  225. HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE);
  226. CONSOLE_SCREEN_BUFFER_INFO console_info;
  227. if((stderr_hnd != INVALID_HANDLE_VALUE) &&
  228. GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) {
  229. /*
  230. * Do not use +1 to get the true screen-width since writing a
  231. * character at the right edge will cause a line wrap.
  232. */
  233. cols = (int)
  234. (console_info.srWindow.Right - console_info.srWindow.Left);
  235. }
  236. }
  237. #endif /* TIOCGSIZE */
  238. if(cols > 20)
  239. bar->width = cols;
  240. }
  241. if(!bar->width)
  242. bar->width = 79;
  243. else if(bar->width > MAX_BARLENGTH)
  244. bar->width = MAX_BARLENGTH;
  245. bar->out = config->global->errors;
  246. bar->tick = 150;
  247. bar->barmove = 1;
  248. }