gnulib: fix argp --help formatting

This is a patch that was sent by Simon Reinhardt to gnulib and has
never been applied.  It fixes a several formatting issues in --help.
https://lists.gnu.org/archive/html/bug-gnulib/2016-02/msg00013.html

* lib/argp-fmtstream.c (__argp_fmtstream_update): Flush output as soon
as possible.
* lib/argp-fmtstream.h (struct argp_fmtstream): Member point_offs is
no longer needed.
* lib/argp-help.c (indent_to): Flush output to avoid a spurious
newline before an overlong word.
This commit is contained in:
Alexandre Duret-Lutz 2025-02-06 21:51:09 +01:00
parent 27fb175276
commit d0e404fec0
3 changed files with 56 additions and 157 deletions

View file

@ -68,7 +68,6 @@ __argp_make_fmtstream (FILE *stream,
fs->rmargin = rmargin; fs->rmargin = rmargin;
fs->wmargin = wmargin; fs->wmargin = wmargin;
fs->point_col = 0; fs->point_col = 0;
fs->point_offs = 0;
fs->buf = (char *) malloc (INIT_BUF_SIZE); fs->buf = (char *) malloc (INIT_BUF_SIZE);
if (! fs->buf) if (! fs->buf)
@ -115,8 +114,19 @@ weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
#endif #endif
#endif #endif
/* Process FS's buffer so that line wrapping is done from POINT_OFFS to the
end of its buffer. This code is mostly from glibc stdio/linewrap.c. */ static void
write_block (argp_fmtstream_t fs, char *buf, int len)
{
#ifdef _LIBC
__fxprintf (fs->stream, "%.*s", len, buf);
#else
fwrite_unlocked (buf, 1, len, fs->stream);
#endif
}
/* Process FS's buffer so that line wrapping is done and flush all of it. So
after return fs->p will be set to fb->buf. */
void void
__argp_fmtstream_update (argp_fmtstream_t fs) __argp_fmtstream_update (argp_fmtstream_t fs)
{ {
@ -124,7 +134,7 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
size_t len; size_t len;
/* Scan the buffer for newlines. */ /* Scan the buffer for newlines. */
buf = fs->buf + fs->point_offs; buf = fs->buf;
while (buf < fs->p) while (buf < fs->p)
{ {
size_t r; size_t r;
@ -132,31 +142,10 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
if (fs->point_col == 0 && fs->lmargin != 0) if (fs->point_col == 0 && fs->lmargin != 0)
{ {
/* We are starting a new line. Print spaces to the left margin. */ /* We are starting a new line. Print spaces to the left margin. */
const size_t pad = fs->lmargin; size_t i;
if (fs->p + pad < fs->end) for (i = 0; i < fs->lmargin; i++)
{ write_block(fs, " ", 1);
/* We can fit in them in the buffer by moving the fs->point_col = fs->lmargin;
buffer text up and filling in the beginning. */
memmove (buf + pad, buf, fs->p - buf);
fs->p += pad; /* Compensate for bigger buffer. */
memset (buf, ' ', pad); /* Fill in the spaces. */
buf += pad; /* Don't bother searching them. */
}
else
{
/* No buffer space for spaces. Must flush. */
size_t i;
for (i = 0; i < pad; i++)
{
#ifdef _LIBC
if (_IO_fwide (fs->stream, 0) > 0)
putwc_unlocked (L' ', fs->stream);
else
#endif
putc_unlocked (' ', fs->stream);
}
}
fs->point_col = pad;
} }
len = fs->p - buf; len = fs->p - buf;
@ -172,8 +161,9 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
if (fs->point_col + len < fs->rmargin) if (fs->point_col + len < fs->rmargin)
{ {
/* The remaining buffer text is a partial line and fits /* The remaining buffer text is a partial line and fits
within the maximum line width. Advance point for the within the maximum line width. Output the line and increment
characters to be written and stop scanning. */ point. */
write_block(fs, buf, len);
fs->point_col += len; fs->point_col += len;
break; break;
} }
@ -185,7 +175,9 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin) else if (fs->point_col + (nl - buf) < (ssize_t) fs->rmargin)
{ {
/* The buffer contains a full line that fits within the maximum /* The buffer contains a full line that fits within the maximum
line width. Reset point and scan the next line. */ line width. Output the line, reset point and scan the next
line. */
write_block(fs, buf, nl + 1 - buf);
fs->point_col = 0; fs->point_col = 0;
buf = nl + 1; buf = nl + 1;
continue; continue;
@ -196,23 +188,23 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
if (fs->wmargin < 0) if (fs->wmargin < 0)
{ {
/* Truncate the line by overwriting the excess with the /* Truncated everything past the right margin. */
newline and anything after it in the buffer. */
if (nl < fs->p) if (nl < fs->p)
{ {
memmove (buf + (r - fs->point_col), nl, fs->p - nl); write_block(fs, buf, r - fs->point_col);
fs->p -= buf + (r - fs->point_col) - nl; write_block(fs, "\n", 1);
/* Reset point for the next line and start scanning it. */ /* Reset point for the next line and start scanning it. */
fs->point_col = 0; fs->point_col = 0;
buf += r + 1; /* Skip full line plus \n. */ buf = nl + 1; /* Skip full line plus \n. */
continue;
} }
else else
{ {
/* The buffer ends with a partial line that is beyond the /* The buffer ends with a partial line that is beyond the
maximum line width. Advance point for the characters maximum line width. Advance point for the characters
written, and discard those past the max from the buffer. */ written, and discard those past the max from the buffer. */
fs->point_col += len; write_block(fs, buf, r - fs->point_col);
fs->p -= fs->point_col - r; fs->point_col += len;
break; break;
} }
} }
@ -249,99 +241,26 @@ __argp_fmtstream_update (argp_fmtstream_t fs)
do do
++p; ++p;
while (p < nl && !isblank ((unsigned char) *p)); while (p < nl && !isblank ((unsigned char) *p));
if (p == nl) nl = p;
{ nextline = nl + 1;
/* It already ends a line. No fussing required. */ }
fs->point_col = 0;
buf = nl + 1;
continue;
}
/* We will move the newline to replace the first blank. */
nl = p;
/* Swallow separating blanks. */
do
++p;
while (isblank ((unsigned char) *p));
/* The next line will start here. */
nextline = p;
}
/* Note: There are a bunch of tests below for write_block(fs, buf, nl - buf);
NEXTLINE == BUF + LEN + 1; this case is where NL happens to fall if (nextline < fs->p)
at the end of the buffer, and NEXTLINE is in fact empty (and so {
we need not be careful to maintain its contents). */ /* There are more lines to process. Do line break and print
blanks up to the wrap margin. */
if ((nextline == buf + len + 1 write_block(fs, "\n", 1);
? fs->end - nl < fs->wmargin + 1 for (i = 0; i < fs->wmargin; ++i)
: nextline - (nl + 1) < fs->wmargin) write_block(fs, " ", 1);
&& fs->p > nextline) fs->point_col = fs->wmargin;
{ }
/* The margin needs more blanks than we removed. */ buf = nextline;
if (fs->end - fs->p > fs->wmargin + 1) }
/* Make some space for them. */
{
size_t mv = fs->p - nextline;
memmove (nl + 1 + fs->wmargin, nextline, mv);
nextline = nl + 1 + fs->wmargin;
len = nextline + mv - buf;
*nl++ = '\n';
}
else
/* Output the first line so we can use the space. */
{
#ifdef _LIBC
__fxprintf (fs->stream, "%.*s\n",
(int) (nl - fs->buf), fs->buf);
#else
if (nl > fs->buf)
fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream);
putc_unlocked ('\n', fs->stream);
#endif
len += buf - fs->buf;
nl = buf = fs->buf;
}
}
else
/* We can fit the newline and blanks in before
the next word. */
*nl++ = '\n';
if (nextline - nl >= fs->wmargin
|| (nextline == buf + len + 1 && fs->end - nextline >= fs->wmargin))
/* Add blanks up to the wrap margin column. */
for (i = 0; i < fs->wmargin; ++i)
*nl++ = ' ';
else
for (i = 0; i < fs->wmargin; ++i)
#ifdef _LIBC
if (_IO_fwide (fs->stream, 0) > 0)
putwc_unlocked (L' ', fs->stream);
else
#endif
putc_unlocked (' ', fs->stream);
/* Copy the tail of the original buffer into the current buffer
position. */
if (nl < nextline)
memmove (nl, nextline, buf + len - nextline);
len -= nextline - buf;
/* Continue the scan on the remaining lines in the buffer. */
buf = nl;
/* Restore bufp to include all the remaining text. */
fs->p = nl + len;
/* Reset the counter of what has been output this line. If wmargin
is 0, we want to avoid the lmargin getting added, so we set
point_col to a magic value of -1 in that case. */
fs->point_col = fs->wmargin ? fs->wmargin : -1;
}
} }
/* Remember that we've scanned as far as the end of the buffer. */ /* Remember that we've flushed everything. */
fs->point_offs = fs->p - fs->buf; fs->p = fs->buf;
} }
/* Ensure that FS has space for AMOUNT more bytes in its buffer, either by /* Ensure that FS has space for AMOUNT more bytes in its buffer, either by
@ -351,30 +270,9 @@ __argp_fmtstream_ensure (struct argp_fmtstream *fs, size_t amount)
{ {
if ((size_t) (fs->end - fs->p) < amount) if ((size_t) (fs->end - fs->p) < amount)
{ {
ssize_t wrote;
/* Flush FS's buffer. */ /* Flush FS's buffer. */
__argp_fmtstream_update (fs); __argp_fmtstream_update (fs);
#ifdef _LIBC
__fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf);
wrote = fs->p - fs->buf;
#else
wrote = fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
#endif
if (wrote == fs->p - fs->buf)
{
fs->p = fs->buf;
fs->point_offs = 0;
}
else
{
fs->p -= wrote;
fs->point_offs -= wrote;
memmove (fs->buf, fs->buf + wrote, fs->p - fs->buf);
return 0;
}
if ((size_t) (fs->end - fs->buf) < amount) if ((size_t) (fs->end - fs->buf) < amount)
/* Gotta grow the buffer. */ /* Gotta grow the buffer. */
{ {

View file

@ -95,9 +95,7 @@ struct argp_fmtstream
size_t lmargin, rmargin; /* Left and right margins. */ size_t lmargin, rmargin; /* Left and right margins. */
ssize_t wmargin; /* Margin to wrap to, or -1 to truncate. */ ssize_t wmargin; /* Margin to wrap to, or -1 to truncate. */
/* Point in buffer to which we've processed for wrapping, but not output. */ /* Output column at buf, or -1 meaning 0 but don't add lmargin. */
size_t point_offs;
/* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin. */
ssize_t point_col; ssize_t point_col;
char *buf; /* Output buffer. */ char *buf; /* Output buffer. */
@ -250,7 +248,7 @@ ARGP_FS_EI size_t
__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin) __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin)
{ {
size_t __old; size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) if (__fs->p > __fs->buf)
__argp_fmtstream_update (__fs); __argp_fmtstream_update (__fs);
__old = __fs->lmargin; __old = __fs->lmargin;
__fs->lmargin = __lmargin; __fs->lmargin = __lmargin;
@ -262,7 +260,7 @@ ARGP_FS_EI size_t
__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin) __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin)
{ {
size_t __old; size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) if (__fs->p > __fs->buf)
__argp_fmtstream_update (__fs); __argp_fmtstream_update (__fs);
__old = __fs->rmargin; __old = __fs->rmargin;
__fs->rmargin = __rmargin; __fs->rmargin = __rmargin;
@ -274,7 +272,7 @@ ARGP_FS_EI size_t
__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin) __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
{ {
size_t __old; size_t __old;
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) if (__fs->p > __fs->buf)
__argp_fmtstream_update (__fs); __argp_fmtstream_update (__fs);
__old = __fs->wmargin; __old = __fs->wmargin;
__fs->wmargin = __wmargin; __fs->wmargin = __wmargin;
@ -285,7 +283,7 @@ __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
ARGP_FS_EI size_t ARGP_FS_EI size_t
__argp_fmtstream_point (argp_fmtstream_t __fs) __argp_fmtstream_point (argp_fmtstream_t __fs)
{ {
if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs) if (__fs->p > __fs->buf)
__argp_fmtstream_update (__fs); __argp_fmtstream_update (__fs);
return __fs->point_col >= 0 ? __fs->point_col : 0; return __fs->point_col >= 0 ? __fs->point_col : 0;
} }

View file

@ -931,6 +931,9 @@ indent_to (argp_fmtstream_t stream, unsigned col)
int needed = col - __argp_fmtstream_point (stream); int needed = col - __argp_fmtstream_point (stream);
while (needed-- > 0) while (needed-- > 0)
__argp_fmtstream_putc (stream, ' '); __argp_fmtstream_putc (stream, ' ');
/* Flush stream to avoid spurious newline before overlong word
(see argp-test.c). */
__argp_fmtstream_update(stream);
} }
/* Output to STREAM either a space, or a newline if there isn't room for at /* Output to STREAM either a space, or a newline if there isn't room for at