/* Word-wrapping and line-truncating streams
- Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1997-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written by Miles Bader <miles@gnu.ai.mit.edu>.
The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If not,
- write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
/* This package emulates glibc `line_wrap_stream' semantics for systems that
don't have that. */
#ifdef HAVE_CONFIG_H
-#include <config.h>
+# include <config.h>
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>
-#include "argp-fmtstream.h"
+#include <argp-fmtstream.h>
#include "argp-namefrob.h"
#ifndef ARGP_FMTSTREAM_USE_LINEWRAP
#define isblank(ch) ((ch)==' ' || (ch)=='\t')
#endif
-#if defined _LIBC && defined USE_IN_LIBIO
+#ifdef _LIBC
+# include <wchar.h>
# include <libio/libioP.h>
-# define __vsnprintf(s, l, f, a) _IO_vsnprintf (s, l, f, a)
#endif
#define INIT_BUF_SIZE 200
__argp_make_fmtstream (FILE *stream,
size_t lmargin, size_t rmargin, ssize_t wmargin)
{
- argp_fmtstream_t fs = malloc (sizeof (struct argp_fmtstream));
- if (fs)
+ argp_fmtstream_t fs;
+
+ fs = (struct argp_fmtstream *) malloc (sizeof (struct argp_fmtstream));
+ if (fs != NULL)
{
fs->stream = stream;
fs->point_col = 0;
fs->point_offs = 0;
- fs->buf = malloc (INIT_BUF_SIZE);
+ fs->buf = (char *) malloc (INIT_BUF_SIZE);
if (! fs->buf)
{
free (fs);
return fs;
}
+#if 0
+/* Not exported. */
#ifdef weak_alias
weak_alias (__argp_make_fmtstream, argp_make_fmtstream)
#endif
+#endif
/* Flush FS to its stream, and free it (but don't close the stream). */
void
{
__argp_fmtstream_update (fs);
if (fs->p > fs->buf)
- fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
+ {
+#ifdef _LIBC
+ __fxprintf (fs->stream, "%.*s", (int) (fs->p - fs->buf), fs->buf);
+#else
+ fwrite_unlocked (fs->buf, 1, fs->p - fs->buf, fs->stream);
+#endif
+ }
free (fs->buf);
free (fs);
}
+#if 0
+/* Not exported. */
#ifdef weak_alias
weak_alias (__argp_fmtstream_free, argp_fmtstream_free)
#endif
+#endif
\f
/* 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. */
/* No buffer space for spaces. Must flush. */
size_t i;
for (i = 0; i < pad; i++)
- putc_unlocked (' ', fs->stream);
+ {
+#ifdef _LIBC
+ if (_IO_fwide (fs->stream, 0) > 0)
+ putwc_unlocked (L' ', fs->stream);
+ else
+#endif
+ putc_unlocked (' ', fs->stream);
+ }
}
fs->point_col = pad;
}
if (nextline > buf)
{
/* Swallow separating blanks. */
- if (p > buf)
+ if (p >= buf)
do
--p;
- while (p > buf && isblank (*p));
+ while (p >= buf && isblank (*p));
nl = p + 1; /* The newline will replace the first blank. */
}
else
at the end of the buffer, and NEXTLINE is in fact empty (and so
we need not be careful to maintain its contents). */
- if (nextline == buf + len + 1
- ? fs->end - nl < fs->wmargin + 1
- : nextline - (nl + 1) < fs->wmargin)
- /* The margin needs more blanks than we removed. */
- 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. */
- {
- if (nl > fs->buf)
- fwrite_unlocked (fs->buf, 1, nl - fs->buf, fs->stream);
- putc_unlocked ('\n', fs->stream);
- len += buf - fs->buf;
- nl = buf = fs->buf;
- }
+ if ((nextline == buf + len + 1
+ ? fs->end - nl < fs->wmargin + 1
+ : nextline - (nl + 1) < fs->wmargin)
+ && fs->p > nextline)
+ {
+ /* The margin needs more blanks than we removed. */
+ 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++ = ' ';
else
for (i = 0; i < fs->wmargin; ++i)
- putc_unlocked (' ', fs->stream);
+#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. */
/* Flush FS's buffer. */
__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;
if ((size_t) (fs->end - fs->buf) < amount)
/* Gotta grow the buffer. */
{
- size_t new_size = fs->end - fs->buf + amount;
- char *new_buf = realloc (fs->buf, new_size);
+ size_t old_size = fs->end - fs->buf;
+ size_t new_size = old_size + amount;
+ char *new_buf;
- if (! new_buf)
+ if (new_size < old_size || ! (new_buf = realloc (fs->buf, new_size)))
{
__set_errno (ENOMEM);
return 0;
__argp_fmtstream_printf (struct argp_fmtstream *fs, const char *fmt, ...)
{
int out;
+ size_t avail;
size_t size_guess = PRINTF_SIZE_GUESS; /* How much space to reserve. */
do
if (! __argp_fmtstream_ensure (fs, size_guess))
return -1;
- size_guess += size_guess;
va_start (args, fmt);
- out = __vsnprintf (fs->p, fs->end - fs->p, fmt, args);
+ avail = fs->end - fs->p;
+ out = __vsnprintf_internal (fs->p, avail, fmt, args, 0);
va_end (args);
+ if ((size_t) out >= avail)
+ size_guess = out + 1;
}
- while (out == -1);
+ while ((size_t) out >= avail);
fs->p += out;
return out;
}
+#if 0
+/* Not exported. */
#ifdef weak_alias
weak_alias (__argp_fmtstream_printf, argp_fmtstream_printf)
#endif
+#endif
#endif /* !ARGP_FMTSTREAM_USE_LINEWRAP */