From 6a2b9a278838c7d52ceb75ca316a56dca3661532 Mon Sep 17 00:00:00 2001 From: Andrew Wood Date: Sun, 27 Jul 2025 19:53:28 +0100 Subject: [PATCH] Add an alias for the name for %N to the display sub-structure, so that the name can be varied between displays without having to alter the control value (#165). --- src/include/pv-internal.h | 10 ++++++++++ src/pv/display.c | 4 ++-- src/pv/format/name.c | 4 ++-- src/pv/state.c | 14 ++++++++++++++ src/pv/watchpid.c | 1 + 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index 4c38807..895eec6 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -245,6 +245,14 @@ struct pvstate_s { /***************** * Display state * *****************/ + /* + * Note that the "name" pointer is an alias - it should point to + * some other string that's allocated and freed separately, such as + * control.name. It is used here so that the name can be changed + * for different display structures without having to also change + * the control structure, for example when watching multiple file + * descriptors with --watchfd. + */ struct pvdisplay_s { struct pvdisplay_segment_s { /* format string broken into segments */ @@ -273,6 +281,8 @@ struct pvstate_s { off_t initial_offset; /* offset when first opened (when watching fds) */ size_t next_line_len; /* length of currently receiving line so far */ + /*@dependent@*/ /*@null@*/ const char *name; /* copy of pointer to string for %N */ + size_t format_segment_count; /* number of format string segments */ pvtransfercount_t count_type; /* type of count for transfer, rate, etc */ diff --git a/src/pv/display.c b/src/pv/display.c index 8c0a176..c3f562d 100644 --- a/src/pv/display.c +++ b/src/pv/display.c @@ -1044,8 +1044,8 @@ bool pv_format(pvprogramstatus_t status, readonly_pvcontrol_t control, readonly_ size_t new_size; new_size = (size_t) ((4 * control->width) + 80); - if (NULL != control->name) - new_size += strlen(control->name); /* flawfinder: ignore */ + if (NULL != display->name) + new_size += strlen(display->name); /* flawfinder: ignore */ /* flawfinder: name is always set by pv_strdup(), which bounds with a \0. */ new_buffer = malloc(new_size + 16); diff --git a/src/pv/format/name.c b/src/pv/format/name.c index 9f60369..c2d377b 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->control->name) { - (void) pv_snprintf(content, sizeof(content), string_format, args->control->name); + if (args->display->name) { + (void) pv_snprintf(content, sizeof(content), string_format, args->display->name); } return pv_formatter_segmentcontent(content, args); diff --git a/src/pv/state.c b/src/pv/state.c index 2bd726b..fa34196 100644 --- a/src/pv/state.c +++ b/src/pv/state.c @@ -177,6 +177,11 @@ void pv_state_free(pvstate_t state) free(state->display.display_buffer); state->display.display_buffer = NULL; + if (NULL != state->display.name) { + /* The display name pointer is an alias, so don't free it. */ + state->display.name = NULL; + } + if (NULL != state->extra_display.display_buffer) free(state->extra_display.display_buffer); state->extra_display.display_buffer = NULL; @@ -299,6 +304,11 @@ void pv_state_set_format(pvstate_t state, bool progress, bool timer, bool eta, b if (NULL != name) state->control.name = pv_strdup(name); + /*@-onlytrans@ *//* splint correctly warns about possibly leaking memory. */ + /* Alias this new name pointer, even if it's NULL, to display.name. */ + state->display.name = state->control.name; + /*@+onlytrans@ */ + /* Tell pv_format() that the format has changed. */ state->flags.reparse_display = 1; } @@ -442,6 +452,10 @@ void pv_state_name_set(pvstate_t state, /*@null@ */ const char *val) } if (NULL != val) state->control.name = pv_strdup(val); + /*@-onlytrans@ *//* splint correctly warns about possibly leaking memory. */ + /* display.name is an alias - don't free it. */ + state->display.name = state->control.name; + /*@+onlytrans@ */ } void pv_state_default_bar_style_set(pvstate_t state, /*@null@ */ const char *val) diff --git a/src/pv/watchpid.c b/src/pv/watchpid.c index 6045c40..a51510b 100644 --- a/src/pv/watchpid.c +++ b/src/pv/watchpid.c @@ -516,6 +516,7 @@ int pv_watchpid_scanfds(pvstate_t state, /*@-mustfreeonly@ *//* splint - this is not a leak, this is a new entry. */ info_array[use_idx].state->display.display_buffer = NULL; info_array[use_idx].state->display.display_buffer_size = 0; + info_array[use_idx].state->display.name = NULL; info_array[use_idx].state->calc.history = NULL; info_array[use_idx].state->calc.history_len = 0; /*@+mustfreeonly@ */