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).

This commit is contained in:
Andrew Wood
2025-07-26 22:28:39 +01:00
parent 18548d217b
commit ecc0c0e414
13 changed files with 86 additions and 87 deletions
+13 -11
View File
@@ -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 */
+11 -5
View File
@@ -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);
+5 -5
View File
@@ -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. */
+4 -4
View File
@@ -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";
+4 -5
View File
@@ -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
+5 -8
View File
@@ -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(). */
+3 -4
View File
@@ -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
+3 -4
View File
@@ -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);
+2 -2
View File
@@ -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);
+15 -17
View File
@@ -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 {
+5 -7
View File
@@ -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. */
+1 -1
View File
@@ -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;
+15 -14
View File
@@ -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);