From c9dede08d45f9fe8b8308cfd6a914e99fa9b3c96 Mon Sep 17 00:00:00 2001 From: Andrew Wood Date: Tue, 19 Mar 2024 22:17:43 +0000 Subject: [PATCH] Adjust the decimal units flag variable name from "si" to "decimal_units" so it does not overlap with other words like "size" and "signal"; add man page entry and adjust the "-L" man page entry; and allow this flag to also change how input prefixes are processed. --- docs/NEWS.md | 1 + docs/pv.1 | 15 ++++++++--- docs/pv.1.md | 13 ++++++++-- src/include/options.h | 4 +-- src/include/pv-internal.h | 4 +-- src/include/pv.h | 12 +++++---- src/main/help.c | 2 +- src/main/main.c | 4 +-- src/main/options.c | 22 ++++++++-------- src/pv/cursor.c | 4 +-- src/pv/display.c | 4 +-- src/pv/number.c | 54 ++++++++++++++++++++++++++++----------- src/pv/state.c | 6 ++--- 13 files changed, 95 insertions(+), 50 deletions(-) diff --git a/docs/NEWS.md b/docs/NEWS.md index 5df7461..5a5ad4b 100644 --- a/docs/NEWS.md +++ b/docs/NEWS.md @@ -1,5 +1,6 @@ ### NOT YET RELEASED + * feature: new "`--si`" option to display and interpret size suffixes in multiples of 1000 rather than 1024 (pull request [#85](https://codeberg.org/a-j-wood/pv/pulls/85)) supplied by [kevinruddy](https://codeberg.org/kevinruddy) * i18n: corrections and missing strings added to French translations (pull request [#83](https://codeberg.org/a-j-wood/pv/pulls/83)) supplied by [Thomas Bertels](https://codeberg.org/tbertels) ### 1.8.5 - 19 November 2023 diff --git a/docs/pv.1 b/docs/pv.1 index 0285054..395e033 100644 --- a/docs/pv.1 +++ b/docs/pv.1 @@ -1,4 +1,4 @@ -.TH PV 1 "November 2023" Linux "User Manuals" +.TH PV 1 "March 2024" Linux "User Manuals" .SH NAME pv \- monitor the progress of data through a pipe .SH SYNOPSIS @@ -154,6 +154,11 @@ data transferred so far. Display the total bits instead of the total bytes. The output suffix will be "b" instead of "B". .TP +.B \-k, \-\-si +Display and interpret suffixes as multiples of 1000 rather than the default +of 1024. Note that this only takes effect on options after this one, so for +consistency, specify this option first. +.TP .B \-T, \-\-buffer\-percent Turn on the transfer buffer percentage display. This will show the percentage of the transfer buffer in use - but see the caveat under @@ -343,7 +348,11 @@ invocations in a single, long, pipeline. Limit the transfer to a maximum of .I RATE bytes per second. A suffix of "K", "M", "G", or "T" can be added to denote -kibibytes (*1024), mebibytes, and so on. +kibibytes (*1024), mebibytes, and so on. If +.B \-\-si +was also passed, suffixes will denote kilobytes (*1000), megabytes, etc. +Note the caveat about the positioning of +.B \-\-si . .TP .BI \-B\ BYTES \fR,\ \fB\-\-buffer-size\ BYTES Use a transfer buffer size of @@ -716,7 +725,7 @@ home page: .BR O_DIRECT ) .SH COPYRIGHT -Copyright \(co 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood. +Copyright \(co 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood. License GPLv3+: GNU GPL version 3 or later . diff --git a/docs/pv.1.md b/docs/pv.1.md index 0bf302f..47d027e 100644 --- a/docs/pv.1.md +++ b/docs/pv.1.md @@ -121,6 +121,12 @@ that are explicitly switched on will be shown. : Display the total bits instead of the total bytes. The output suffix will be \"b\" instead of \"B\". +**-k, \--si** + +: Display and interpret suffixes as multiples of 1000 rather than the + default of 1024. Note that this only takes effect on options after + this one, so for consistency, specify this option first. + **-T, \--buffer-percent** : Turn on the transfer buffer percentage display. This will show the @@ -255,7 +261,9 @@ that are explicitly switched on will be shown. : Limit the transfer to a maximum of *RATE* bytes per second. A suffix of \"K\", \"M\", \"G\", or \"T\" can be added to denote kibibytes - (\*1024), mebibytes, and so on. + (\*1024), mebibytes, and so on. If **\--si** was also passed, + suffixes will denote kilobytes (\*1000), megabytes, etc. Note the + caveat about the positioning of **\--si .** **-B BYTES, \--buffer-size BYTES** @@ -535,7 +543,8 @@ Alternatively, use the issue tracker linked from the **pv** home page: # COPYRIGHT -Copyright © 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood. +Copyright © 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew +Wood. License GPLv3+: GNU GPL version 3 or later \. diff --git a/src/include/options.h b/src/include/options.h index 6d5e696..5e019f3 100644 --- a/src/include/options.h +++ b/src/include/options.h @@ -1,7 +1,7 @@ /* * Global program option structure and the parsing function prototype. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -34,7 +34,7 @@ struct opts_s { /* structure describing run-time options */ bool average_rate; /* average rate counter flag */ bool bytes; /* bytes transferred flag */ bool bits; /* report transfer size in bits */ - bool si; /* decimal prefix flag */ + bool decimal_units; /* decimal prefix flag */ bool bufpercent; /* transfer buffer percentage flag */ size_t lastwritten; /* show N bytes last written */ bool force; /* force-if-not-terminal flag */ diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index 21f67d4..e9778d5 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -1,7 +1,7 @@ /* * Functions internal to the PV library. Include "config.h" first. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -105,7 +105,7 @@ struct pvstate_s { bool wait; /* wait for data before display */ bool linemode; /* count lines instead of bytes */ bool bits; /* report bits instead of bytes */ - bool si; /* use decimal prefixes */ + bool decimal_units; /* use decimal prefixes */ bool null_terminated_lines; /* lines are null-terminated */ bool no_display; /* do nothing other than pipe data */ unsigned int skip_errors; /* skip read errors counter */ diff --git a/src/include/pv.h b/src/include/pv.h index 7ef5234..a4cd902 100644 --- a/src/include/pv.h +++ b/src/include/pv.h @@ -1,7 +1,7 @@ /* * Functions used across the program. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -49,15 +49,17 @@ typedef enum { extern double pv_getnum_interval(const char *); /* - * Return the given string converted to an off_t, for use as a size. + * Return the given string converted to an off_t, for use as a size, + * optionally interpreting suffixes in decimal units (multiples of 1000) + * instead of multiples of 1024. */ -extern off_t pv_getnum_size(const char *); +extern off_t pv_getnum_size(const char *, bool); /* * Return the given string converted to an unsigned integer, for use as a * count such as screen width. */ -extern unsigned int pv_getnum_count(const char *); +extern unsigned int pv_getnum_count(const char *, bool); /* * Return true if the given string is a number of the given type. NB an @@ -164,7 +166,7 @@ extern void pv_state_wait_set(pvstate_t, bool); extern void pv_state_delay_start_set(pvstate_t, double); extern void pv_state_linemode_set(pvstate_t, bool); extern void pv_state_bits_set(pvstate_t, bool); -extern void pv_state_si_set(pvstate_t, bool); +extern void pv_state_decimal_units_set(pvstate_t, bool); extern void pv_state_null_terminated_lines_set(pvstate_t, bool); extern void pv_state_no_display_set(pvstate_t, bool); extern void pv_state_skip_errors_set(pvstate_t, unsigned int); diff --git a/src/main/help.c b/src/main/help.c index fcad22e..90cf9c7 100644 --- a/src/main/help.c +++ b/src/main/help.c @@ -308,7 +308,7 @@ void display_help(void) N_("show number of bits transferred"), { 0, 0, 0, 0} }, { "-k", "--si", NULL, - N_("show sizes in powers of 1000 (e.g., 1.1G)"), + N_("treat suffixes as multiples of 1000 rather than 1024"), { 0, 0, 0, 0} }, { "-T", "--buffer-percent", NULL, N_("show percentage of transfer buffer in use"), diff --git a/src/main/main.c b/src/main/main.c index de5fadf..be1b63a 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -2,7 +2,7 @@ * Main program entry point - read the command line options, then perform * the appropriate actions. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -278,7 +278,7 @@ int main(int argc, char **argv) pv_state_delay_start_set(state, opts->delay_start); pv_state_linemode_set(state, opts->linemode); pv_state_bits_set(state, opts->bits); - pv_state_si_set(state, opts->si); + pv_state_decimal_units_set(state, opts->decimal_units); pv_state_null_terminated_lines_set(state, opts->null_terminated_lines); pv_state_skip_errors_set(state, opts->skip_errors); pv_state_error_skip_block_set(state, opts->error_skip_block); diff --git a/src/main/options.c b/src/main/options.c index 482d511..a0be278 100644 --- a/src/main/options.c +++ b/src/main/options.c @@ -1,7 +1,7 @@ /* * Parse command-line options. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -337,7 +337,7 @@ opts_t opts_parse(unsigned int argc, char **argv) numopts++; break; case 'k': - opts->si = true; + opts->decimal_units = true; break; case 'T': opts->bufpercent = true; @@ -345,7 +345,7 @@ opts_t opts_parse(unsigned int argc, char **argv) opts->no_splice = true; break; case 'A': - opts->lastwritten = (size_t) pv_getnum_count(optarg); + opts->lastwritten = (size_t) pv_getnum_count(optarg, opts->decimal_units); numopts++; opts->no_splice = true; break; @@ -391,7 +391,7 @@ opts_t opts_parse(unsigned int argc, char **argv) /*@+mustfreefresh@ */ } } else { - opts->size = pv_getnum_size(optarg); + opts->size = pv_getnum_size(optarg, opts->decimal_units); } break; case 'l': @@ -405,11 +405,11 @@ opts_t opts_parse(unsigned int argc, char **argv) opts->interval = pv_getnum_interval(optarg); break; case 'w': - opts->width = pv_getnum_count(optarg); + opts->width = pv_getnum_count(optarg, opts->decimal_units); opts->width_set_manually = opts->width == 0 ? false : true; break; case 'H': - opts->height = pv_getnum_count(optarg); + opts->height = pv_getnum_count(optarg, opts->decimal_units); opts->height_set_manually = opts->height == 0 ? false : true; break; case 'N': @@ -421,10 +421,10 @@ opts_t opts_parse(unsigned int argc, char **argv) } break; case 'L': - opts->rate_limit = pv_getnum_size(optarg); + opts->rate_limit = pv_getnum_size(optarg, opts->decimal_units); break; case 'B': - opts->buffer_size = (size_t) pv_getnum_size(optarg); + opts->buffer_size = (size_t) pv_getnum_size(optarg, opts->decimal_units); opts->no_splice = true; break; case 'C': @@ -434,7 +434,7 @@ opts_t opts_parse(unsigned int argc, char **argv) opts->skip_errors++; break; case 'Z': - opts->error_skip_block = pv_getnum_size(optarg); + opts->error_skip_block = pv_getnum_size(optarg, opts->decimal_units); break; case 'S': opts->stop_at_size = true; @@ -450,7 +450,7 @@ opts_t opts_parse(unsigned int argc, char **argv) opts->no_splice = true; break; case 'R': - opts->remote = pv_getnum_count(optarg); + opts->remote = pv_getnum_count(optarg, false); break; case 'P': opts->pidfile = pv_strdup(optarg); @@ -477,7 +477,7 @@ opts_t opts_parse(unsigned int argc, char **argv) opts->watch_fd = parse_fd; break; case 'm': - opts->average_rate_window = pv_getnum_count(optarg); + opts->average_rate_window = pv_getnum_count(optarg, opts->decimal_units); break; #ifdef ENABLE_DEBUGGING case '!': diff --git a/src/pv/cursor.c b/src/pv/cursor.c index 74de1eb..1b73233 100644 --- a/src/pv/cursor.c +++ b/src/pv/cursor.c @@ -10,7 +10,7 @@ * terminal, so we try to use a lockfile if terminal locking doesn't work, * and finally abort if even that is unavailable. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -293,7 +293,7 @@ static int pv_crs_get_ypos(int terminalfd) } #endif /* !CURSOR_ANSWERBACK_BYTE_BY_BYTE */ - ypos = (int) pv_getnum_count(cpr + 2); + ypos = (int) pv_getnum_count(cpr + 2, false); if (0 != tcsetattr(terminalfd, TCSANOW | TCSAFLUSH, &old_tty)) { debug("%s: %s", "tcsetattr (2) failed", strerror(errno)); diff --git a/src/pv/display.c b/src/pv/display.c index c65e3c4..9e27711 100644 --- a/src/pv/display.c +++ b/src/pv/display.c @@ -1,7 +1,7 @@ /* * Display functions. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -836,7 +836,7 @@ static bool pv__format(pvstate_t state, long double elapsed_sec, off_t bytes_sin count_type = PV_TRANSFERCOUNT_BYTES; if (state->control.linemode) count_type = PV_TRANSFERCOUNT_LINES; - else if (state->control.si) + else if (state->control.decimal_units) count_type = PV_TRANSFERCOUNT_DECBYTES; switch (component_type) { diff --git a/src/pv/number.c b/src/pv/number.c index 2eda015..edbf97d 100644 --- a/src/pv/number.c +++ b/src/pv/number.c @@ -1,7 +1,7 @@ /* * Functions for converting strings to numbers. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -27,14 +27,16 @@ static bool pv__isdigit(char c) * Return the numeric value of "str", as an off_t, where "str" is expected * to be a sequence of digits (without a thousands separator), possibly with * a fractional part, optionally followed by a units suffix such as "K" for - * kibibytes. + * kibibytes. If "decimal_units" is true, suffixes are interpreted as + * multiples of 1000, rather than multiples of 1024. */ -off_t pv_getnum_size(const char *str) +off_t pv_getnum_size(const char *str, bool decimal_units) { off_t integral_part = 0; off_t fractional_part = 0; unsigned int fractional_divisor = 1; - unsigned int shift = 0; + unsigned int binary_shift = 0; + off_t decimal_multiplier = 0; if (NULL == str) return (off_t) 0; @@ -74,7 +76,7 @@ off_t pv_getnum_size(const char *str) /* * Parse any units given (K=KiB=*1024, M=MiB=1024KiB, G=GiB=1024MiB, - * T=TiB=1024GiB). + * T=TiB=1024GiB; replace 1024 with 1000 if decimal_units is true). */ if (str[0] != '\0') { /* Skip any spaces or tabs after the digits. */ @@ -83,19 +85,23 @@ off_t pv_getnum_size(const char *str) switch (str[0]) { case 'k': case 'K': - shift = 10; + binary_shift = 10; + decimal_multiplier = 1000; break; case 'm': case 'M': - shift = 20; + binary_shift = 20; + decimal_multiplier = 1000000; break; case 'g': case 'G': - shift = 30; + binary_shift = 30; + decimal_multiplier = 1000000000; break; case 't': case 'T': - shift = 40; + binary_shift = 40; + decimal_multiplier = 1000000000000; break; default: break; @@ -103,14 +109,24 @@ off_t pv_getnum_size(const char *str) } /* - * Binary left-shift the supplied number by "shift" times, i.e. + * If decimal_units is false, zero decimal_multiplier; if true, zero + * binary_shift. This is so we only do one or the other. + */ + if (decimal_units) { + binary_shift = 0; + } else { + decimal_multiplier = 0; + } + + /* + * Binary left-shift the supplied number by "binary_shift" times, i.e. * apply the given units (KiB, MiB, etc) to it, but never shift left * more than 30 at a time to avoid overflows. */ - while (shift > 0) { + while (binary_shift > 0) { unsigned int shiftby; - shiftby = shift; + shiftby = binary_shift; if (shiftby > 30) shiftby = 30; @@ -124,7 +140,15 @@ off_t pv_getnum_size(const char *str) fractional_part = (off_t) (fractional_part << shiftby); /*@+shiftimplementation@ */ - shift -= shiftby; + binary_shift -= shiftby; + } + + /* + * Multiply the supplied number by the decimal multiplier. + */ + if (decimal_multiplier > 0) { + integral_part = integral_part * decimal_multiplier; + fractional_part = fractional_part * decimal_multiplier; } /* @@ -183,9 +207,9 @@ double pv_getnum_interval(const char *str) * rules as pv_getnum_size(), expecting "str" to express a value to be used * as a count (such as number of screen columns, or size of a buffer). */ -unsigned int pv_getnum_count(const char *str) +unsigned int pv_getnum_count(const char *str, bool decimal_units) { - return (unsigned int) pv_getnum_size(str); + return (unsigned int) pv_getnum_size(str, decimal_units); } diff --git a/src/pv/state.c b/src/pv/state.c index 0e60eac..cae353a 100644 --- a/src/pv/state.c +++ b/src/pv/state.c @@ -1,7 +1,7 @@ /* * State management functions. * - * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023 Andrew Wood + * Copyright 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood * * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. */ @@ -234,9 +234,9 @@ void pv_state_bits_set(pvstate_t state, bool bits) state->control.bits = bits; } -void pv_state_si_set(pvstate_t state, bool si) +void pv_state_decimal_units_set(pvstate_t state, bool decimal_units) { - state->control.si = si; + state->control.decimal_units = decimal_units; } void pv_state_null_terminated_lines_set(pvstate_t state, bool val)