From ecc0c0e414d9adb0efecc2da0c58fe3b1ab55728 Mon Sep 17 00:00:00 2001 From: Andrew Wood Date: Sat, 26 Jul 2025 22:28:39 +0100 Subject: [PATCH] Adjust the readonly structure pointer types so the pointer itself is not read-only but the thing it points to is; and change the display formatters to use pointers to control, transfer, and calc structures instead of the whole state, with read-only access enforced at compile time (#165). --- src/include/pv-internal.h | 24 +++++++++++++----------- src/pv/display.c | 16 +++++++++++----- src/pv/format/averagerate.c | 10 +++++----- src/pv/format/barstyle.c | 8 ++++---- src/pv/format/bufferpercent.c | 9 ++++----- src/pv/format/bytes.c | 13 +++++-------- src/pv/format/eta.c | 7 +++---- src/pv/format/fineta.c | 7 +++---- src/pv/format/name.c | 4 ++-- src/pv/format/progressbar.c | 32 +++++++++++++++----------------- src/pv/format/rate.c | 12 +++++------- src/pv/format/sgr.c | 2 +- src/pv/format/timer.c | 29 +++++++++++++++-------------- 13 files changed, 86 insertions(+), 87 deletions(-) diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index 037a18e..052e602 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -445,24 +445,26 @@ typedef struct pvtransferstate_s *pvtransferstate_t; * function declarations where the function definitely shouldn't be altering * the contents of the structure. */ -typedef const struct pvprogramstatus_s * const readonly_pvprogramstatus_t; -typedef const struct pvinputfiles_s * const readonly_pvinputfiles_t; -typedef const struct pvcontrol_s * const readonly_pvcontrol_t; -typedef const struct pvsignal_s * const readonly_pvsignal_t; -typedef const struct pvtransientflags_s * const readonly_pvtransientflags_t; -typedef const struct pvdisplay_s * const readonly_pvdisplay_t; -typedef const struct pvdisplay_segment_s * const readonly_pvdisplay_segment_t; -typedef const struct pvtransfercalc_s * const readonly_pvtransfercalc_t; -typedef const struct pvcursorstate_s * const readonly_pvcursorstate_t; -typedef const struct pvtransferstate_s * const readonly_pvtransferstate_t; +typedef const struct pvprogramstatus_s * readonly_pvprogramstatus_t; +typedef const struct pvinputfiles_s * readonly_pvinputfiles_t; +typedef const struct pvcontrol_s * readonly_pvcontrol_t; +typedef const struct pvsignal_s * readonly_pvsignal_t; +typedef const struct pvtransientflags_s * readonly_pvtransientflags_t; +typedef const struct pvdisplay_s * readonly_pvdisplay_t; +typedef const struct pvdisplay_segment_s * readonly_pvdisplay_segment_t; +typedef const struct pvtransfercalc_s * readonly_pvtransfercalc_t; +typedef const struct pvcursorstate_s * readonly_pvcursorstate_t; +typedef const struct pvtransferstate_s * readonly_pvtransferstate_t; /* * Structure containing the parameters used by formatters. */ struct pvformatter_args_s { - /*@dependent@*/ pvstate_t state; /* overall state */ /*@dependent@*/ pvdisplay_t display; /* the display being updated */ /*@dependent@*/ pvdisplay_segment_t segment; /* the segment of the display */ + /*@dependent@*/ readonly_pvcontrol_t control; /* program control settings */ + /*@dependent@*/ readonly_pvtransferstate_t transfer; /* transfer state */ + /*@dependent@*/ readonly_pvtransfercalc_t calc; /* calculated transfer state */ /*@dependent@*/ char *buffer; /* buffer to write formatted segments into */ pvdisplay_bytecount_t buffer_size; /* size of the buffer */ pvdisplay_bytecount_t offset; /* current write position in the buffer */ diff --git a/src/pv/display.c b/src/pv/display.c index 9264164..933cb92 100644 --- a/src/pv/display.c +++ b/src/pv/display.c @@ -140,7 +140,7 @@ void pv_write_retry(int fd, const char *buf, size_t count) * Write the given buffer to the terminal, like pv_write_retry(), unless * stderr is suspended. */ -void pv_tty_write(readonly_pvtransientflags_t flags, const char * buf, size_t count) +void pv_tty_write(readonly_pvtransientflags_t flags, const char *buf, size_t count) { while (0 == flags->suspend_stderr && count > 0) { ssize_t nwritten; @@ -779,9 +779,11 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp memset(&formatter_info, 0, sizeof(formatter_info)); dummy_buffer[0] = '\0'; - formatter_info.state = state; formatter_info.display = display; formatter_info.segment = &(display->format[segment]); + formatter_info.control = &(state->control); + formatter_info.transfer = &(state->transfer); + formatter_info.calc = &(state->calc); formatter_info.buffer = dummy_buffer; formatter_info.buffer_size = 0; formatter_info.offset = 0; @@ -936,11 +938,13 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl if (NULL == display) return false; - formatter_info.state = state; formatter_info.display = display; formatter_info.buffer = display_segments; formatter_info.buffer_size = sizeof(display_segments); formatter_info.offset = 0; + formatter_info.control = &(state->control); + formatter_info.transfer = &(state->transfer); + formatter_info.calc = &(state->calc); format_component_array = pv__format_components(); @@ -1233,7 +1237,8 @@ void pv_display(pvstate_t state, bool final) } } else { if (state->control.force || pv_in_foreground()) { - pv_tty_write(&(state->flags), state->display.display_buffer, state->display.display_string_bytes); + pv_tty_write(&(state->flags), state->display.display_buffer, + state->display.display_string_bytes); pv_tty_write(&(state->flags), "\r", 1); state->display.output_produced = true; } @@ -1246,7 +1251,8 @@ void pv_display(pvstate_t state, bool final) && (NULL != state->extra_display.display_buffer) ) { pv_tty_write(&(state->flags), "\033]2;", 4); - pv_tty_write(&(state->flags), state->extra_display.display_buffer, state->extra_display.display_string_bytes); + pv_tty_write(&(state->flags), state->extra_display.display_buffer, + state->extra_display.display_string_bytes); pv_tty_write(&(state->flags), "\033\\", 2); state->extra_display.output_produced = true; debug("%s: [%s]", "windowtitle display", state->extra_display.display_buffer); diff --git a/src/pv/format/averagerate.c b/src/pv/format/averagerate.c index e217036..6fd4d11 100644 --- a/src/pv/format/averagerate.c +++ b/src/pv/format/averagerate.c @@ -24,18 +24,18 @@ pvdisplay_bytecount_t pv_formatter_average_rate(pvformatter_args_t args) return 0; /*@-mustfreefresh@ */ - if (args->state->control.numeric) { + if (args->control->numeric) { /* numeric - raw value without suffix. */ (void) pv_snprintf(content, sizeof(content), - "%.4Lf", ((args->state->control.bits ? 8.0 : 1.0) * args->state->calc.average_rate)); - } else if (args->state->control.bits && !args->state->control.linemode) { + "%.4Lf", ((args->control->bits ? 8.0 : 1.0) * args->calc->average_rate)); + } else if (args->control->bits && !args->control->linemode) { /* bits per second */ pv_describe_amount(content, sizeof(content), - "(%s)", 8 * args->state->calc.average_rate, "", _("b/s"), args->display->count_type); + "(%s)", 8 * args->calc->average_rate, "", _("b/s"), args->display->count_type); } else { /* bytes or lines per second */ pv_describe_amount(content, - sizeof(content), "(%s)", args->state->calc.average_rate, _("/s"), _("B/s"), + sizeof(content), "(%s)", args->calc->average_rate, _("/s"), _("B/s"), args->display->count_type); } /*@+mustfreefresh@ *//* splint: see above. */ diff --git a/src/pv/format/barstyle.c b/src/pv/format/barstyle.c index 615cb2b..be77e99 100644 --- a/src/pv/format/barstyle.c +++ b/src/pv/format/barstyle.c @@ -44,7 +44,7 @@ static bool pv_barstyle(pvformatter_args_t args, pvbarstyle_t style, const char memset(style, 0, sizeof(*style)); - if (args->state->control.can_display_utf8 && 0 == strcmp(name, "block")) { + if (args->control->can_display_utf8 && 0 == strcmp(name, "block")) { style->style_id = 2; @@ -58,7 +58,7 @@ static bool pv_barstyle(pvformatter_args_t args, pvbarstyle_t style, const char return true; - } else if (args->state->control.can_display_utf8 && 0 == strcmp(name, "granular")) { + } else if (args->control->can_display_utf8 && 0 == strcmp(name, "granular")) { style->style_id = 3; @@ -79,7 +79,7 @@ static bool pv_barstyle(pvformatter_args_t args, pvbarstyle_t style, const char return true; - } else if (args->state->control.can_display_utf8 && 0 == strcmp(name, "shaded")) { + } else if (args->control->can_display_utf8 && 0 == strcmp(name, "shaded")) { style->style_id = 4; @@ -164,7 +164,7 @@ pvdisplay_bytecount_t pv_formatter_bar_default(pvformatter_args_t args) { if (0 == args->segment->parameter) { const char *default_name; - default_name = args->state->control.default_bar_style; + default_name = args->control->default_bar_style; /*@-branchstate@ */ if (NULL == default_name) default_name = "plain"; diff --git a/src/pv/format/bufferpercent.c b/src/pv/format/bufferpercent.c index 2916a27..1c15da5 100644 --- a/src/pv/format/bufferpercent.c +++ b/src/pv/format/bufferpercent.c @@ -23,16 +23,15 @@ pvdisplay_bytecount_t pv_formatter_buffer_percent(pvformatter_args_t args) if (0 == args->buffer_size) return 0; - if (args->state->transfer.buffer_size > 0) { + if (args->transfer->buffer_size > 0) { double pct_used = pv_percentage((off_t) - (args->state->transfer.read_position - - args->state->transfer.write_position), + (args->transfer->read_position - args->transfer->write_position), (off_t) - (args->state->transfer.buffer_size)); + (args->transfer->buffer_size)); (void) pv_snprintf(content, sizeof(content), "{%3.0f%%}", pct_used); } #ifdef HAVE_SPLICE - if (args->state->transfer.splice_used) + if (args->transfer->splice_used) (void) pv_snprintf(content, sizeof(content), "{%s}", "----"); #endif diff --git a/src/pv/format/bytes.c b/src/pv/format/bytes.c index c36477d..e93e01a 100644 --- a/src/pv/format/bytes.c +++ b/src/pv/format/bytes.c @@ -26,20 +26,17 @@ pvdisplay_bytecount_t pv_formatter_bytes(pvformatter_args_t args) content[0] = '\0'; /*@-mustfreefresh@ */ - if (args->state->control.numeric) { + if (args->control->numeric) { /* Numeric mode - raw values only, no suffix. */ (void) pv_snprintf(content, sizeof(content), - "%lld", - (long long) ((args->state->control.bits ? 8 : 1) * - args->state->transfer.transferred)); - } else if (args->state->control.bits && !args->state->control.linemode) { + "%lld", (long long) ((args->control->bits ? 8 : 1) * args->transfer->transferred)); + } else if (args->control->bits && !args->control->linemode) { pv_describe_amount(content, sizeof(content), "%s", - (long double) (args->state->transfer.transferred * 8), "", _("b"), + (long double) (args->transfer->transferred * 8), "", _("b"), args->display->count_type); } else { pv_describe_amount(content, sizeof(content), "%s", - (long double) (args->state->transfer.transferred), "", _("B"), - args->display->count_type); + (long double) (args->transfer->transferred), "", _("B"), args->display->count_type); } /*@+mustfreefresh@ *//* splint - false positive from gettext(). */ diff --git a/src/pv/format/eta.c b/src/pv/format/eta.c index b58d274..4e1df63 100644 --- a/src/pv/format/eta.c +++ b/src/pv/format/eta.c @@ -24,16 +24,15 @@ pvdisplay_bytecount_t pv_formatter_eta(pvformatter_args_t args) /* * Don't try to calculate this if the size is not known. */ - if (args->state->control.size < 1) + if (args->control->size < 1) return 0; if (0 == args->buffer_size) return 0; eta = - pv_seconds_remaining((args->state->transfer.transferred - args->display->initial_offset), - args->state->control.size - args->display->initial_offset, - args->state->calc.current_avg_rate); + pv_seconds_remaining((args->transfer->transferred - args->display->initial_offset), + args->control->size - args->display->initial_offset, args->calc->current_avg_rate); /* * Bounds check, so we don't overrun the suffix buffer. This means diff --git a/src/pv/format/fineta.c b/src/pv/format/fineta.c index a21ebe8..39090f6 100644 --- a/src/pv/format/fineta.c +++ b/src/pv/format/fineta.c @@ -32,7 +32,7 @@ pvdisplay_bytecount_t pv_formatter_fineta(pvformatter_args_t args) /* * Don't try to calculate this if the size is not known. */ - if (args->state->control.size < 1) + if (args->control->size < 1) return 0; if (0 == args->buffer_size) @@ -47,9 +47,8 @@ pvdisplay_bytecount_t pv_formatter_fineta(pvformatter_args_t args) * lookup. */ - eta = pv_seconds_remaining(args->state->transfer.transferred - args->display->initial_offset, - args->state->control.size - args->display->initial_offset, - args->state->calc.current_avg_rate); + eta = pv_seconds_remaining(args->transfer->transferred - args->display->initial_offset, + args->control->size - args->display->initial_offset, args->calc->current_avg_rate); /* Bounds check - see pv_formatter_eta(). */ eta = pv_bound_long(eta, 0, (long) 360000000L); diff --git a/src/pv/format/name.c b/src/pv/format/name.c index 4b659c7..9f60369 100644 --- a/src/pv/format/name.c +++ b/src/pv/format/name.c @@ -35,8 +35,8 @@ pvdisplay_bytecount_t pv_formatter_name(pvformatter_args_t args) (void) pv_snprintf(string_format, sizeof(string_format), "%%%d.500s:", field_width); content[0] = '\0'; - if (args->state->control.name) { - (void) pv_snprintf(content, sizeof(content), string_format, args->state->control.name); + if (args->control->name) { + (void) pv_snprintf(content, sizeof(content), string_format, args->control->name); } return pv_formatter_segmentcontent(content, args); diff --git a/src/pv/format/progressbar.c b/src/pv/format/progressbar.c index f183b29..d4d9225 100644 --- a/src/pv/format/progressbar.c +++ b/src/pv/format/progressbar.c @@ -74,28 +74,26 @@ static pvdisplay_bytecount_t pv_formatter_progress_knownsize(pvformatter_args_t memset(after_bar, 0, sizeof(after_bar)); - if (args->state->control.size > 0) { + if (args->control->size > 0) { /* Percentage of data transferred. */ - bar_percentage = (double) (args->state->calc.percentage); + bar_percentage = (double) (args->calc->percentage); (void) pv_snprintf(after_bar, sizeof(after_bar), " %3ld%%", (int) bar_percentage); } else { /* Current rate vs max rate. */ bar_percentage = 0.0; - if (args->state->calc.rate_max > 0) { - bar_percentage = - (double) (100.0 * args->state->calc.transfer_rate / args->state->calc.rate_max); + if (args->calc->rate_max > 0) { + bar_percentage = (double) (100.0 * args->calc->transfer_rate / args->calc->rate_max); } /*@-mustfreefresh@ */ - if (args->state->control.bits && !args->state->control.linemode) { + if (args->control->bits && !args->control->linemode) { /* bits per second */ pv_describe_amount(after_bar, sizeof(after_bar), "/%s", - 8.0 * args->state->calc.rate_max, "", _("b/s"), args->display->count_type); + 8.0 * args->calc->rate_max, "", _("b/s"), args->display->count_type); } else { /* bytes or lines per second */ pv_describe_amount(after_bar, sizeof(after_bar), - "/%s", args->state->calc.rate_max, _("/s"), _("B/s"), - args->display->count_type); + "/%s", args->calc->rate_max, _("/s"), _("B/s"), args->display->count_type); } /*@+mustfreefresh@ *//* splint: see above about gettext(). */ } @@ -247,7 +245,7 @@ static pvdisplay_bytecount_t pv_formatter_progress_unknownsize(pvformatter_args_ * here we make values above 100 send the indicator back down again, * so it moves back and forth. */ - indicator_position = args->state->calc.percentage; + indicator_position = args->calc->percentage; if (indicator_position > 200.0) #if HAVE_FMOD indicator_position = fmod(indicator_position, 200.0); @@ -316,7 +314,7 @@ pvdisplay_bytecount_t pv_formatter_progress(pvformatter_args_t args) if (0 == args->segment->parameter) { const char *default_name; - default_name = args->state->control.default_bar_style; + default_name = args->control->default_bar_style; /*@-branchstate@ */ if (NULL == default_name) default_name = "plain"; @@ -328,7 +326,7 @@ pvdisplay_bytecount_t pv_formatter_progress(pvformatter_args_t args) if (0 == args->buffer_size) return 0; - if (args->state->control.size > 0 || args->state->control.rate_gauge) { + if (args->control->size > 0 || args->control->rate_gauge) { /* Known size or rate gauge - bar with percentage. */ bytes = pv_formatter_progress_knownsize(args, content, sizeof(content), true, true, true); } else { @@ -354,7 +352,7 @@ pvdisplay_bytecount_t pv_formatter_progress_bar_only(pvformatter_args_t args) if (0 == args->segment->parameter) { const char *default_name; - default_name = args->state->control.default_bar_style; + default_name = args->control->default_bar_style; /*@-branchstate@ */ if (NULL == default_name) default_name = "plain"; @@ -366,7 +364,7 @@ pvdisplay_bytecount_t pv_formatter_progress_bar_only(pvformatter_args_t args) if (0 == args->buffer_size) return 0; - if (args->state->control.size > 0 || args->state->control.rate_gauge) { + if (args->control->size > 0 || args->control->rate_gauge) { /* Known size or rate gauge - bar with percentage. */ bytes = pv_formatter_progress_knownsize(args, content, sizeof(content), false, true, false); } else { @@ -393,12 +391,12 @@ pvdisplay_bytecount_t pv_formatter_progress_amount_only(pvformatter_args_t args) if (0 == args->buffer_size) return 0; - if (args->state->control.numeric) { + if (args->control->numeric) { /* Numeric mode - percentage as a rounded integer with no suffix. */ - (void) pv_snprintf(content, sizeof(content), "%.0f", args->state->calc.percentage); + (void) pv_snprintf(content, sizeof(content), "%.0f", args->calc->percentage); bytes = strlen(content); /* flawfinder: ignore */ /* flawfinder: always \0-terminated by pv_snprintf() and the earlier memset(). */ - } else if (args->state->control.size > 0 || args->state->control.rate_gauge) { + } else if (args->control->size > 0 || args->control->rate_gauge) { /* Known size or rate gauge - percentage or rate. */ bytes = pv_formatter_progress_knownsize(args, content, sizeof(content), false, false, true); } else { diff --git a/src/pv/format/rate.c b/src/pv/format/rate.c index 5574247..9d92543 100644 --- a/src/pv/format/rate.c +++ b/src/pv/format/rate.c @@ -26,20 +26,18 @@ pvdisplay_bytecount_t pv_formatter_rate(pvformatter_args_t args) return 0; /*@-mustfreefresh@ */ - if (args->state->control.numeric) { + if (args->control->numeric) { /* numeric - raw value without suffix. */ (void) pv_snprintf(content, sizeof(content), - "%.4Lf", - ((args->state->control.bits ? 8.0 : 1.0) * args->state->calc.transfer_rate)); - } else if (args->state->control.bits && !args->state->control.linemode) { + "%.4Lf", ((args->control->bits ? 8.0 : 1.0) * args->calc->transfer_rate)); + } else if (args->control->bits && !args->control->linemode) { /* bits per second */ pv_describe_amount(content, sizeof(content), "[%s]", - 8 * args->state->calc.transfer_rate, "", _("b/s"), args->display->count_type); + 8 * args->calc->transfer_rate, "", _("b/s"), args->display->count_type); } else { /* bytes or lines per second */ pv_describe_amount(content, sizeof(content), - "[%s]", args->state->calc.transfer_rate, _("/s"), _("B/s"), - args->display->count_type); + "[%s]", args->calc->transfer_rate, _("/s"), _("B/s"), args->display->count_type); } /*@+mustfreefresh@ *//* splint: see above. */ diff --git a/src/pv/format/sgr.c b/src/pv/format/sgr.c index 40b607f..6ecc810 100644 --- a/src/pv/format/sgr.c +++ b/src/pv/format/sgr.c @@ -109,7 +109,7 @@ pvdisplay_bytecount_t pv_formatter_sgr(pvformatter_args_t args) args->display->format_uses_colour = true; - if (!args->state->control.can_display_colour) + if (!args->control->can_display_colour) return 0; if (NULL == args->segment->string_parameter) return 0; diff --git a/src/pv/format/timer.c b/src/pv/format/timer.c index 829cf26..7965cfe 100644 --- a/src/pv/format/timer.c +++ b/src/pv/format/timer.c @@ -17,6 +17,7 @@ pvdisplay_bytecount_t pv_formatter_timer(pvformatter_args_t args) { char content[128]; /* flawfinder: ignore - always bounded */ + long double elapsed_seconds; args->display->showing_timer = true; @@ -25,22 +26,24 @@ pvdisplay_bytecount_t pv_formatter_timer(pvformatter_args_t args) if (0 == args->buffer_size) return 0; + elapsed_seconds = args->transfer->elapsed_seconds; + /* * Bounds check, so we don't overrun the prefix buffer. This does * mean that the timer will stop at a 100,000 hours, but since * that's 11 years, it shouldn't be a problem. */ - if (args->state->transfer.elapsed_seconds > (long double) 360000000.0L) - args->state->transfer.elapsed_seconds = (long double) 360000000.0L; + if (elapsed_seconds > (long double) 360000000.0L) + elapsed_seconds = (long double) 360000000.0L; /* Also check it's not negative. */ - if (args->state->transfer.elapsed_seconds < 0.0) - args->state->transfer.elapsed_seconds = 0.0; + if (elapsed_seconds < 0.0) + elapsed_seconds = 0.0; - if (args->state->control.numeric) { + if (args->control->numeric) { /* Numeric mode - show the number of seconds, unformatted. */ - (void) pv_snprintf(content, sizeof(content), "%.4Lf", args->state->transfer.elapsed_seconds); - } else if (args->state->transfer.elapsed_seconds > (long double) 86400.0L) { + (void) pv_snprintf(content, sizeof(content), "%.4Lf", elapsed_seconds); + } else if (elapsed_seconds > (long double) 86400.0L) { /* * If the elapsed time is more than a day, include a day count as * well as hours, minutes, and seconds. @@ -48,17 +51,15 @@ pvdisplay_bytecount_t pv_formatter_timer(pvformatter_args_t args) (void) pv_snprintf(content, sizeof(content), "%ld:%02ld:%02ld:%02ld", - ((long) (args->state->transfer.elapsed_seconds)) / 86400, - (((long) (args->state->transfer.elapsed_seconds)) / 3600) % - 24, (((long) (args->state->transfer.elapsed_seconds)) / 60) % 60, - ((long) (args->state->transfer.elapsed_seconds)) % 60); + ((long) (elapsed_seconds)) / 86400, + (((long) (elapsed_seconds)) / 3600) % + 24, (((long) (elapsed_seconds)) / 60) % 60, ((long) (elapsed_seconds)) % 60); } else { (void) pv_snprintf(content, sizeof(content), "%ld:%02ld:%02ld", - ((long) (args->state->transfer.elapsed_seconds)) / 3600, - (((long) (args->state->transfer.elapsed_seconds)) / 60) % 60, - ((long) (args->state->transfer.elapsed_seconds)) % 60); + ((long) (elapsed_seconds)) / 3600, + (((long) (elapsed_seconds)) / 60) % 60, ((long) (elapsed_seconds)) % 60); } return pv_formatter_segmentcontent(content, args);