Add a "--gauge" option which alters the progress bar to show the current rate as a percentage of the max rate seen, if the size is unknown (#46).

This commit is contained in:
Andrew Wood
2024-10-04 22:15:14 +01:00
parent fbe726e4c4
commit c548d1f2d8
15 changed files with 361 additions and 255 deletions
+1
View File
@@ -66,6 +66,7 @@ struct opts_s {
bool cursor; /* whether to use cursor positioning */
bool numeric; /* numeric output only */
bool wait; /* wait for transfer before display */
bool rate_gauge; /* if size unknown, show rate vs max rate */
bool linemode; /* count lines instead of bytes */
bool null_terminated_lines; /* lines are null-terminated */
bool no_display; /* do nothing other than pipe data */
+1
View File
@@ -123,6 +123,7 @@ struct pvstate_s {
bool cursor; /* use cursor positioning */
bool numeric; /* numeric output only */
bool wait; /* wait for data before display */
bool rate_gauge; /* if size unknown, show rate vs max rate */
bool linemode; /* count lines instead of bytes */
bool bits; /* report bits instead of bytes */
bool decimal_units; /* use decimal prefixes */
+1
View File
@@ -183,6 +183,7 @@ extern void pv_state_show_stats_set(pvstate_t, bool);
extern void pv_state_numeric_set(pvstate_t, bool);
extern void pv_state_wait_set(pvstate_t, bool);
extern void pv_state_delay_start_set(pvstate_t, double);
extern void pv_state_rate_gauge_set(pvstate_t, bool);
extern void pv_state_linemode_set(pvstate_t, bool);
extern void pv_state_bits_set(pvstate_t, bool);
extern void pv_state_decimal_units_set(pvstate_t, bool);
+3
View File
@@ -338,6 +338,9 @@ void display_help(void)
{ "-s", "--size", N_("SIZE"),
N_("set estimated data size to SIZE bytes"),
{ 0, 0, 0, 0} },
{ "-g", "--gauge", NULL,
N_("if size unknown, show rate vs max rate"),
{ 0, 0, 0, 0} },
{ "-l", "--line-mode", NULL,
N_("count lines instead of bytes"),
{ 0, 0, 0, 0} },
+1
View File
@@ -310,6 +310,7 @@ int main(int argc, char **argv)
pv_state_numeric_set(state, opts->numeric);
pv_state_wait_set(state, opts->wait);
pv_state_delay_start_set(state, opts->delay_start);
pv_state_rate_gauge_set(state, opts->rate_gauge);
pv_state_linemode_set(state, opts->linemode);
pv_state_bits_set(state, opts->bits);
pv_state_decimal_units_set(state, opts->decimal_units);
+5 -1
View File
@@ -283,6 +283,7 @@ opts_t opts_parse(unsigned int argc, char **argv)
{ "wait", 0, NULL, (int) 'W' },
{ "delay-start", 1, NULL, (int) 'D' },
{ "size", 1, NULL, (int) 's' },
{ "gauge", 0, NULL, (int) 'g' },
{ "line-mode", 0, NULL, (int) 'l' },
{ "null", 0, NULL, (int) '0' },
{ "interval", 1, NULL, (int) 'i' },
@@ -313,7 +314,7 @@ opts_t opts_parse(unsigned int argc, char **argv)
/*@+nullassign@ */
int option_index = 0;
#endif /* HAVE_GETOPT_LONG */
char *short_options = "hVpteIrab8kTA:fvnqcWD:s:l0i:w:H:N:F:L:B:CEZ:SYKXR:P:d:m:o:"
char *short_options = "hVpteIrab8kTA:fvnqcWD:s:gl0i:w:H:N:F:L:B:CEZ:SYKXR:P:d:m:o:"
#ifdef ENABLE_DEBUGGING
"!:"
#endif
@@ -546,6 +547,9 @@ opts_t opts_parse(unsigned int argc, char **argv)
}
}
break;
case 'g':
opts->rate_gauge = true;
break;
case 'l':
opts->linemode = true;
break;
+54 -20
View File
@@ -607,6 +607,7 @@ bool pv_format(pvstate_t state, bool final)
size_t segment;
size_t new_display_string_len;
const char *formatstr;
pv__transfercount_t count_type;
/* Quick safety check - state must exist. */
if (NULL == state)
@@ -626,6 +627,13 @@ bool pv_format(pvstate_t state, bool final)
if (NULL == formatstr)
return false;
/* Determine the type of thing being counted for transfer, rate, etc. */
count_type = PV_TRANSFERCOUNT_BYTES;
if (state->control.linemode)
count_type = PV_TRANSFERCOUNT_LINES;
else if (state->control.decimal_units)
count_type = PV_TRANSFERCOUNT_DECBYTES;
/*
* Reallocate output buffer if width changes.
*/
@@ -745,7 +753,6 @@ bool pv_format(pvstate_t state, bool final)
time_t then;
struct tm *time_ptr;
char *time_format;
pv__transfercount_t count_type;
if (!state->display.component[component_type].required)
continue;
@@ -766,12 +773,6 @@ bool pv_format(pvstate_t state, bool final)
component_content[0] = '\0';
component_buf_size = PV_SIZEOF_COMPONENT_STR;
count_type = PV_TRANSFERCOUNT_BYTES;
if (state->control.linemode)
count_type = PV_TRANSFERCOUNT_LINES;
else if (state->control.decimal_units)
count_type = PV_TRANSFERCOUNT_DECBYTES;
switch (component_type) {
case PV_COMPONENT_STRING:
@@ -1034,27 +1035,54 @@ bool pv_format(pvstate_t state, bool final)
if (state->display.component[PV_COMPONENT_PROGRESS].required) {
char *component_content;
size_t component_buf_size;
char pct[16]; /* flawfinder: ignore - only populated by pv_snprintf(). */
char after_bar[32]; /* flawfinder: ignore - only populated by pv_snprintf(). */
int available_width, bar_length, pad_count;
component_content = state->display.component[PV_COMPONENT_PROGRESS].content;
component_content[0] = '\0';
component_buf_size = PV_SIZEOF_COMPONENT_STR;
memset(pct, 0, sizeof(pct));
memset(after_bar, 0, sizeof(after_bar));
/* The opening of the bar area. */
(void) pv_snprintf(component_content, component_buf_size, "[");
if (state->control.size > 0 || state->control.rate_gauge) {
/*
* Known size, or rate gauge mode. Show a bar, and
* a percentage (size) or max rate (gauge).
*/
size_t after_bar_width;
int bar_percentage;
if (state->control.size > 0) {
/* Known size; show a bar and a percentage. */
size_t pct_width;
if (state->control.size > 0) {
/* Percentage of data transferred. */
bar_percentage = state->calc.percentage;
(void) pv_snprintf(after_bar, sizeof(after_bar), " %3ld%%", bar_percentage);
} else {
/* Current rate vs max rate. */
bar_percentage = 0;
if (state->calc.rate_max > 0) {
bar_percentage =
(int) (100.0 * state->calc.transfer_rate / state->calc.rate_max);
}
(void) pv_snprintf(pct, sizeof(pct), "%3ld%%", state->calc.percentage);
pct_width = strlen(pct); /* flawfinder: ignore */
/*@-mustfreefresh @ */
if (state->control.bits && !state->control.linemode) {
/* bits per second */
pv__sizestr(after_bar, sizeof(after_bar), "/%s",
8.0 * state->calc.rate_max, "", _("b/s"), count_type);
} else {
/* bytes or lines per second */
pv__sizestr(after_bar, sizeof(after_bar),
"/%s", state->calc.rate_max, _("/s"), _("B/s"), count_type);
}
/*@+mustfreefresh @ */
/* splint: see above about gettext(). */
}
after_bar_width = strlen(after_bar); /* flawfinder: ignore */
/* flawfinder: always \0-terminated by pv_snprintf() and the earlier memset(). */
available_width = (int) (state->control.width) - static_portion_size - (int) (pct_width) - 3;
available_width =
(int) (state->control.width) - static_portion_size - (int) (after_bar_width) - 2;
if (available_width < 0)
available_width = 0;
@@ -1062,8 +1090,11 @@ bool pv_format(pvstate_t state, bool final)
if (available_width > (int) (component_buf_size) - 16)
available_width = (int) (component_buf_size - 16);
/* The opening of the bar area. */
(void) pv_snprintf(component_content, component_buf_size, "[");
/* The bar portion. */
bar_length = (int) ((available_width * state->calc.percentage) / 100 - 1);
bar_length = (int) ((available_width * bar_percentage) / 100 - 1);
for (pad_count = 0; pad_count < bar_length; pad_count++) {
if (pad_count < available_width)
(void) pv_strlcat(component_content, "=", component_buf_size);
@@ -1081,8 +1112,8 @@ bool pv_format(pvstate_t state, bool final)
}
/* The closure of the bar area, and the percentage. */
(void) pv_strlcat(component_content, "] ", component_buf_size);
(void) pv_strlcat(component_content, pct, component_buf_size);
(void) pv_strlcat(component_content, "]", component_buf_size);
(void) pv_strlcat(component_content, after_bar, component_buf_size);
} else {
/* Unknown size; show a moving indicator. */
@@ -1109,6 +1140,9 @@ bool pv_format(pvstate_t state, bool final)
if (indicator_position > 100)
indicator_position = 200 - indicator_position;
/* The opening of the bar area. */
(void) pv_snprintf(component_content, component_buf_size, "[");
/* The spaces before the indicator. */
for (pad_count = 0; pad_count < (available_width * indicator_position) / 100; pad_count++) {
if (pad_count < available_width)
+5
View File
@@ -270,6 +270,11 @@ void pv_state_delay_start_set(pvstate_t state, double val)
state->control.delay_start = val;
}
void pv_state_rate_gauge_set(pvstate_t state, bool val)
{
state->control.rate_gauge = val;
}
void pv_state_linemode_set(pvstate_t state, bool val)
{
state->control.linemode = val;