version 1.50, 2020/01/23 07:10:22 |
version 1.51, 2023/02/22 03:56:43 |
|
|
#include <sys/uio.h> |
#include <sys/uio.h> |
|
|
#include <errno.h> |
#include <errno.h> |
|
#include <limits.h> |
#include <signal.h> |
#include <signal.h> |
|
#include <signal.h> |
#include <stdarg.h> |
#include <stdarg.h> |
|
#include <stdlib.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <string.h> |
#include <string.h> |
#include <time.h> |
#include <time.h> |
|
|
/* determines whether we can output to the terminal */ |
/* determines whether we can output to the terminal */ |
static int can_output(void); |
static int can_output(void); |
|
|
/* formats and inserts the specified size into the given buffer */ |
|
static void format_size(char *, int, off_t); |
|
static void format_rate(char *, int, off_t); |
|
|
|
/* window resizing */ |
/* window resizing */ |
static void sig_winch(int); |
static void sig_winch(int); |
static void setscreensize(void); |
static void setscreensize(void); |
|
|
return (getpgrp() == tcgetpgrp(STDOUT_FILENO)); |
return (getpgrp() == tcgetpgrp(STDOUT_FILENO)); |
} |
} |
|
|
static void |
/* size needed to format integer type v, using (nbits(v) * log2(10) / 10) */ |
format_rate(char *buf, int size, off_t bytes) |
#define STRING_SIZE(v) (((sizeof(v) * 8 * 4) / 10) + 1) |
|
|
|
static const char * |
|
format_rate(off_t bytes) |
{ |
{ |
int i; |
int i; |
|
static char buf[STRING_SIZE(bytes) * 2 + 16]; |
|
|
bytes *= 100; |
bytes *= 100; |
for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++) |
for (i = 0; bytes >= 100*1000 && unit[i] != 'T'; i++) |
|
|
i++; |
i++; |
bytes = (bytes + 512) / 1024; |
bytes = (bytes + 512) / 1024; |
} |
} |
snprintf(buf, size, "%3lld.%1lld%c%s", |
snprintf(buf, sizeof(buf), "%3lld.%1lld%c%s", |
(long long) (bytes + 5) / 100, |
(long long) (bytes + 5) / 100, |
(long long) (bytes + 5) / 10 % 10, |
(long long) (bytes + 5) / 10 % 10, |
unit[i], |
unit[i], |
i ? "B" : " "); |
i ? "B" : " "); |
|
return buf; |
} |
} |
|
|
static void |
static const char * |
format_size(char *buf, int size, off_t bytes) |
format_size(off_t bytes) |
{ |
{ |
int i; |
int i; |
|
static char buf[STRING_SIZE(bytes) + 16]; |
|
|
for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) |
for (i = 0; bytes >= 10000 && unit[i] != 'T'; i++) |
bytes = (bytes + 512) / 1024; |
bytes = (bytes + 512) / 1024; |
snprintf(buf, size, "%4lld%c%s", |
snprintf(buf, sizeof(buf), "%4lld%c%s", |
(long long) bytes, |
(long long) bytes, |
unit[i], |
unit[i], |
i ? "B" : " "); |
i ? "B" : " "); |
|
return buf; |
} |
} |
|
|
void |
void |
refresh_progress_meter(int force_update) |
refresh_progress_meter(int force_update) |
{ |
{ |
char buf[MAX_WINSIZE + 1]; |
char *buf = NULL, *obuf = NULL; |
off_t transferred; |
off_t transferred; |
double elapsed, now; |
double elapsed, now; |
int percent; |
int percent; |
off_t bytes_left; |
off_t bytes_left; |
int cur_speed; |
int cur_speed; |
int hours, minutes, seconds; |
int hours, minutes, seconds; |
int file_len; |
int file_len, cols; |
|
|
if ((!force_update && !alarm_fired && !win_resized) || !can_output()) |
if ((!force_update && !alarm_fired && !win_resized) || !can_output()) |
return; |
return; |
|
|
} else |
} else |
bytes_per_second = cur_speed; |
bytes_per_second = cur_speed; |
|
|
|
last_update = now; |
|
|
|
/* Don't bother if we can't even display the completion percentage */ |
|
if (win_size < 4) |
|
return; |
|
|
/* filename */ |
/* filename */ |
buf[0] = '\0'; |
file_len = cols = win_size - 36; |
file_len = win_size - 36; |
|
if (file_len > 0) { |
if (file_len > 0) { |
buf[0] = '\r'; |
asmprintf(&buf, INT_MAX, &cols, "%-*s", file_len, file); |
snmprintf(buf+1, sizeof(buf)-1, &file_len, "%-*s", |
/* If we used fewer columns than expected then pad */ |
file_len, file); |
if (cols < file_len) |
|
xextendf(&buf, NULL, "%*s", file_len - cols, ""); |
} |
} |
|
|
/* percent of transfer done */ |
/* percent of transfer done */ |
if (end_pos == 0 || cur_pos == end_pos) |
if (end_pos == 0 || cur_pos == end_pos) |
percent = 100; |
percent = 100; |
else |
else |
percent = ((float)cur_pos / end_pos) * 100; |
percent = ((float)cur_pos / end_pos) * 100; |
snprintf(buf + strlen(buf), win_size - strlen(buf), |
|
" %3d%% ", percent); |
|
|
|
/* amount transferred */ |
/* percent / amount transferred / bandwidth usage */ |
format_size(buf + strlen(buf), win_size - strlen(buf), |
xextendf(&buf, NULL, " %3d%% %s %s/s ", percent, format_size(cur_pos), |
cur_pos); |
format_rate((off_t)bytes_per_second)); |
strlcat(buf, " ", win_size); |
|
|
|
/* bandwidth usage */ |
|
format_rate(buf + strlen(buf), win_size - strlen(buf), |
|
(off_t)bytes_per_second); |
|
strlcat(buf, "/s ", win_size); |
|
|
|
/* ETA */ |
/* ETA */ |
if (!transferred) |
if (!transferred) |
stalled += elapsed; |
stalled += elapsed; |
|
|
stalled = 0; |
stalled = 0; |
|
|
if (stalled >= STALL_TIME) |
if (stalled >= STALL_TIME) |
strlcat(buf, "- stalled -", win_size); |
xextendf(&buf, NULL, "- stalled -"); |
else if (bytes_per_second == 0 && bytes_left) |
else if (bytes_per_second == 0 && bytes_left) |
strlcat(buf, " --:-- ETA", win_size); |
xextendf(&buf, NULL, " --:-- ETA"); |
else { |
else { |
if (bytes_left > 0) |
if (bytes_left > 0) |
seconds = bytes_left / bytes_per_second; |
seconds = bytes_left / bytes_per_second; |
|
|
minutes = seconds / 60; |
minutes = seconds / 60; |
seconds -= minutes * 60; |
seconds -= minutes * 60; |
|
|
if (hours != 0) |
if (hours != 0) { |
snprintf(buf + strlen(buf), win_size - strlen(buf), |
xextendf(&buf, NULL, "%d:%02d:%02d", |
"%d:%02d:%02d", hours, minutes, seconds); |
hours, minutes, seconds); |
else |
} else |
snprintf(buf + strlen(buf), win_size - strlen(buf), |
xextendf(&buf, NULL, " %02d:%02d", minutes, seconds); |
" %02d:%02d", minutes, seconds); |
|
|
|
if (bytes_left > 0) |
if (bytes_left > 0) |
strlcat(buf, " ETA", win_size); |
xextendf(&buf, NULL, " ETA"); |
else |
else |
strlcat(buf, " ", win_size); |
xextendf(&buf, NULL, " "); |
} |
} |
|
|
atomicio(vwrite, STDOUT_FILENO, buf, win_size - 1); |
/* Finally, truncate string at window width */ |
last_update = now; |
cols = win_size - 1; |
|
asmprintf(&obuf, INT_MAX, &cols, " %s", buf); |
|
if (obuf != NULL) { |
|
*obuf = '\r'; /* must insert as asmprintf() would escape it */ |
|
atomicio(vwrite, STDOUT_FILENO, obuf, strlen(obuf)); |
|
} |
|
free(buf); |
|
free(obuf); |
} |
} |
|
|
/*ARGSUSED*/ |
/*ARGSUSED*/ |