Correct the wrapping width on lines after the first, improve the commenting, and avoid size_t underflow on very narrow terminals.

This commit is contained in:
Andrew Wood
2026-04-07 22:20:55 +01:00
parent 3eff81f1a6
commit 52585447f0
+65 -10
View File
@@ -54,31 +54,52 @@ static void display_word_wrap_7bit(const char *string, size_t display_width, siz
{
const char *start;
const char *end;
size_t wrap_at_width;
if (NULL == string)
return;
start = string;
wrap_at_width = display_width;
while (strlen(start) > display_width) { /* flawfinder: ignore */
/* Wrap lines that are too long. */
while (strlen(start) > wrap_at_width) { /* flawfinder: ignore */
/* flawfinder rationale: see above. */
end = start + display_width;
/*
* Find the last space before the end of the display line,
* or if there isn't one, behave as if there was one at the
* end of the display line.
*/
end = start + wrap_at_width;
while ((end > start) && (end[0] != ' '))
end--;
if (end == start) {
end = start + display_width;
end = start + wrap_at_width;
} else {
end++;
}
/* Display the string up to that space. */
printf("%.*s", (int) (end - start), start);
if (end == start)
end++;
start = end;
if (start[0] != '\0')
/*
* If there's more text left, start a new display line and
* pad it with spaces to the left margin, and change the
* wrap width to the display width minus the left margin.
*/
if (start[0] != '\0') {
printf("\n%*s", (int) left_margin, "");
if (display_width > left_margin) {
wrap_at_width = display_width - left_margin;
} else {
wrap_at_width = 1;
}
}
}
/* Display the remainder of the string. */
printf("%s", start);
}
@@ -94,6 +115,7 @@ static void display_word_wrap_7bit(const char *string, size_t display_width, siz
static void display_word_wrap(const char *string, size_t display_width, size_t left_margin)
{
#if defined(ENABLE_NLS) && defined(HAVE_WCHAR_H)
size_t wrap_at_width;
size_t wide_char_count;
size_t wide_string_buffer_size;
wchar_t *wide_string;
@@ -102,6 +124,8 @@ static void display_word_wrap(const char *string, size_t display_width, size_t l
if (NULL == string)
return;
/* Calculate how many wide characters are in the multibyte string. */
/*@-nullpass@ */
/* splint note: see mbstowcs() call in pv_strwidth(). */
wide_char_count = mbstowcs(NULL, string, 0);
@@ -112,6 +136,11 @@ static void display_word_wrap(const char *string, size_t display_width, size_t l
return;
}
/*
* Allocate a buffer in which to convert the multibyte string to a
* wide-character string, plus one character for zero padding.
*/
wide_string_buffer_size = sizeof(*wide_string) * (1 + wide_char_count);
wide_string = malloc(wide_string_buffer_size);
if (NULL == wide_string) {
@@ -121,6 +150,8 @@ static void display_word_wrap(const char *string, size_t display_width, size_t l
}
memset(wide_string, 0, wide_string_buffer_size);
/* Convert the multibyte string to a wide-character string. */
if (mbstowcs(wide_string, string, 1 + wide_char_count) == (size_t) -1) {
debug("%s: %s: %s", "mbstowcs", string, strerror(errno));
free(wide_string);
@@ -129,18 +160,27 @@ static void display_word_wrap(const char *string, size_t display_width, size_t l
}
start_idx = 0;
wrap_at_width = display_width;
chars_remaining = wide_char_count;
/* Wrap lines that are too long. */
/*@-unrecog@ *//* splint seems unable to see the prototype for wcswidth(). */
while (chars_remaining > 0 && wcswidth(&(wide_string[start_idx]), chars_remaining) > (int) display_width) {
while (chars_remaining > 0 && wcswidth(&(wide_string[start_idx]), chars_remaining) > (int) wrap_at_width) {
/*@+unrecog@ */
size_t next_idx;
end_idx = start_idx + display_width;
/*
* Find the last space before the end of the display line,
* or if there isn't one, behave as if there was one at the
* end of the display line.
*/
end_idx = start_idx + wrap_at_width;
while ((end_idx > start_idx) && (!iswspace(wide_string[end_idx])))
end_idx--;
if (end_idx == start_idx) {
end_idx = start_idx + display_width;
end_idx = start_idx + wrap_at_width;
} else {
end_idx++;
}
@@ -149,6 +189,7 @@ static void display_word_wrap(const char *string, size_t display_width, size_t l
if (end_idx == start_idx)
next_idx++;
/* Display the string up to that space, a character at a time. */
while (start_idx < end_idx && start_idx < wide_char_count) {
char multi_byte_string[MB_CUR_MAX + 1]; /* flawfinder: ignore */
/*
@@ -165,12 +206,26 @@ static void display_word_wrap(const char *string, size_t display_width, size_t l
}
start_idx = next_idx;
if (start_idx < wide_char_count)
/*
* If there's more text left, start a new display line and
* pad it with spaces to the left margin, and change the
* wrap width to the display width minus the left margin.
*/
if (start_idx < wide_char_count) {
printf("\n%*s", (int) left_margin, "");
chars_remaining = wide_char_count - start_idx;
if (display_width > left_margin) {
wrap_at_width = display_width - left_margin;
} else {
wrap_at_width = 1;
}
chars_remaining = wide_char_count - start_idx;
} else {
/* Explicitly set to 0 to avoid underflow. */
chars_remaining = 0;
}
}
/* Display the remainder of the string, a character at a time. */
while (start_idx < wide_char_count) {
char multi_byte_string[MB_CUR_MAX + 1]; /* flawfinder: ignore */
/* flawfinder rationale as above. */