1/* Word-wrapping and line-truncating streams.
2   Copyright (C) 1997, 2006 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4   Written by Miles Bader <miles@gnu.ai.mit.edu>.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License along
17   with this program; if not, write to the Free Software Foundation,
18   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20/* This package emulates glibc `line_wrap_stream' semantics for systems that
21   don't have that.  If the system does have it, it is just a wrapper for
22   that.  This header file is only used internally while compiling argp, and
23   shouldn't be installed.  */
24
25#ifndef _ARGP_FMTSTREAM_H
26#define _ARGP_FMTSTREAM_H
27
28#include <stdio.h>
29#include <string.h>
30#include <unistd.h>
31
32#ifndef __attribute__
33/* This feature is available in gcc versions 2.5 and later.  */
34# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
35#  define __attribute__(Spec) /* empty */
36# endif
37/* The __-protected variants of `format' and `printf' attributes
38   are accepted by gcc versions 2.6.4 (effectively 2.7) and later.  */
39# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || __STRICT_ANSI__
40#  define __format__ format
41#  define __printf__ printf
42# endif
43#endif
44
45#if    (_LIBC - 0 && !defined (USE_IN_LIBIO)) \
46    || (defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H))
47/* line_wrap_stream is available, so use that.  */
48#define ARGP_FMTSTREAM_USE_LINEWRAP
49#endif
50
51#ifdef ARGP_FMTSTREAM_USE_LINEWRAP
52/* Just be a simple wrapper for line_wrap_stream; the semantics are
53   *slightly* different, as line_wrap_stream doesn't actually make a new
54   object, it just modifies the given stream (reversibly) to do
55   line-wrapping.  Since we control who uses this code, it doesn't matter.  */
56
57#include <linewrap.h>
58
59typedef FILE *argp_fmtstream_t;
60
61#define argp_make_fmtstream line_wrap_stream
62#define __argp_make_fmtstream line_wrap_stream
63#define argp_fmtstream_free line_unwrap_stream
64#define __argp_fmtstream_free line_unwrap_stream
65
66#define __argp_fmtstream_putc(fs,ch) putc(ch,fs)
67#define argp_fmtstream_putc(fs,ch) putc(ch,fs)
68#define __argp_fmtstream_puts(fs,str) fputs(str,fs)
69#define argp_fmtstream_puts(fs,str) fputs(str,fs)
70#define __argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
71#define argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
72#define __argp_fmtstream_printf fprintf
73#define argp_fmtstream_printf fprintf
74
75#define __argp_fmtstream_lmargin line_wrap_lmargin
76#define argp_fmtstream_lmargin line_wrap_lmargin
77#define __argp_fmtstream_set_lmargin line_wrap_set_lmargin
78#define argp_fmtstream_set_lmargin line_wrap_set_lmargin
79#define __argp_fmtstream_rmargin line_wrap_rmargin
80#define argp_fmtstream_rmargin line_wrap_rmargin
81#define __argp_fmtstream_set_rmargin line_wrap_set_rmargin
82#define argp_fmtstream_set_rmargin line_wrap_set_rmargin
83#define __argp_fmtstream_wmargin line_wrap_wmargin
84#define argp_fmtstream_wmargin line_wrap_wmargin
85#define __argp_fmtstream_set_wmargin line_wrap_set_wmargin
86#define argp_fmtstream_set_wmargin line_wrap_set_wmargin
87#define __argp_fmtstream_point line_wrap_point
88#define argp_fmtstream_point line_wrap_point
89
90#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */
91/* Guess we have to define our own version.  */
92
93struct argp_fmtstream
94{
95  FILE *stream;			/* The stream we're outputting to.  */
96
97  size_t lmargin, rmargin;	/* Left and right margins.  */
98  ssize_t wmargin;		/* Margin to wrap to, or -1 to truncate.  */
99
100  /* Point in buffer to which we've processed for wrapping, but not output.  */
101  size_t point_offs;
102  /* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin.  */
103  ssize_t point_col;
104
105  char *buf;			/* Output buffer.  */
106  char *p;			/* Current end of text in BUF. */
107  char *end;			/* Absolute end of BUF.  */
108};
109
110typedef struct argp_fmtstream *argp_fmtstream_t;
111
112/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines
113   written on it with LMARGIN spaces and limits them to RMARGIN columns
114   total.  If WMARGIN >= 0, words that extend past RMARGIN are wrapped by
115   replacing the whitespace before them with a newline and WMARGIN spaces.
116   Otherwise, chars beyond RMARGIN are simply dropped until a newline.
117   Returns NULL if there was an error.  */
118extern argp_fmtstream_t __argp_make_fmtstream (FILE *__stream,
119					       size_t __lmargin,
120					       size_t __rmargin,
121					       ssize_t __wmargin);
122extern argp_fmtstream_t argp_make_fmtstream (FILE *__stream,
123					     size_t __lmargin,
124					     size_t __rmargin,
125					     ssize_t __wmargin);
126
127/* Flush __FS to its stream, and free it (but don't close the stream).  */
128extern void __argp_fmtstream_free (argp_fmtstream_t __fs);
129extern void argp_fmtstream_free (argp_fmtstream_t __fs);
130
131extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs,
132					const char *__fmt, ...)
133     __attribute__ ((__format__ (printf, 2, 3)));
134extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs,
135				      const char *__fmt, ...)
136     __attribute__ ((__format__ (printf, 2, 3)));
137
138extern int __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch);
139extern int argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch);
140
141extern int __argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str);
142extern int argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str);
143
144extern size_t __argp_fmtstream_write (argp_fmtstream_t __fs,
145				      const char *__str, size_t __len);
146extern size_t argp_fmtstream_write (argp_fmtstream_t __fs,
147				    const char *__str, size_t __len);
148
149/* Access macros for various bits of state.  */
150#define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin)
151#define argp_fmtstream_rmargin(__fs) ((__fs)->rmargin)
152#define argp_fmtstream_wmargin(__fs) ((__fs)->wmargin)
153#define __argp_fmtstream_lmargin argp_fmtstream_lmargin
154#define __argp_fmtstream_rmargin argp_fmtstream_rmargin
155#define __argp_fmtstream_wmargin argp_fmtstream_wmargin
156
157/* Set __FS's left margin to LMARGIN and return the old value.  */
158extern size_t argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
159					  size_t __lmargin);
160extern size_t __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
161					    size_t __lmargin);
162
163/* Set __FS's right margin to __RMARGIN and return the old value.  */
164extern size_t argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
165					  size_t __rmargin);
166extern size_t __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
167					    size_t __rmargin);
168
169/* Set __FS's wrap margin to __WMARGIN and return the old value.  */
170extern size_t argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
171					  size_t __wmargin);
172extern size_t __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
173					    size_t __wmargin);
174
175/* Return the column number of the current output point in __FS.  */
176extern size_t argp_fmtstream_point (argp_fmtstream_t __fs);
177extern size_t __argp_fmtstream_point (argp_fmtstream_t __fs);
178
179/* Internal routines.  */
180extern void _argp_fmtstream_update (argp_fmtstream_t __fs);
181extern void __argp_fmtstream_update (argp_fmtstream_t __fs);
182extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
183extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
184
185#ifdef __OPTIMIZE__
186/* Inline versions of above routines.  */
187
188#if !_LIBC
189#define __argp_fmtstream_putc argp_fmtstream_putc
190#define __argp_fmtstream_puts argp_fmtstream_puts
191#define __argp_fmtstream_write argp_fmtstream_write
192#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin
193#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin
194#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin
195#define __argp_fmtstream_point argp_fmtstream_point
196#define __argp_fmtstream_update _argp_fmtstream_update
197#define __argp_fmtstream_ensure _argp_fmtstream_ensure
198#endif
199
200#ifndef ARGP_FS_EI
201#define ARGP_FS_EI extern inline __attribute__ ((__gnu_inline__))
202#endif
203
204ARGP_FS_EI size_t
205__argp_fmtstream_write (argp_fmtstream_t __fs,
206			const char *__str, size_t __len)
207{
208  if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len))
209    {
210      memcpy (__fs->p, __str, __len);
211      __fs->p += __len;
212      return __len;
213    }
214  else
215    return 0;
216}
217
218ARGP_FS_EI int
219__argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str)
220{
221  size_t __len = strlen (__str);
222  if (__len)
223    {
224      size_t __wrote = __argp_fmtstream_write (__fs, __str, __len);
225      return __wrote == __len ? 0 : -1;
226    }
227  else
228    return 0;
229}
230
231ARGP_FS_EI int
232__argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch)
233{
234  if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1))
235    return *__fs->p++ = __ch;
236  else
237    return EOF;
238}
239
240/* Set __FS's left margin to __LMARGIN and return the old value.  */
241ARGP_FS_EI size_t
242__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin)
243{
244  size_t __old;
245  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
246    __argp_fmtstream_update (__fs);
247  __old = __fs->lmargin;
248  __fs->lmargin = __lmargin;
249  return __old;
250}
251
252/* Set __FS's right margin to __RMARGIN and return the old value.  */
253ARGP_FS_EI size_t
254__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin)
255{
256  size_t __old;
257  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
258    __argp_fmtstream_update (__fs);
259  __old = __fs->rmargin;
260  __fs->rmargin = __rmargin;
261  return __old;
262}
263
264/* Set FS's wrap margin to __WMARGIN and return the old value.  */
265ARGP_FS_EI size_t
266__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
267{
268  size_t __old;
269  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
270    __argp_fmtstream_update (__fs);
271  __old = __fs->wmargin;
272  __fs->wmargin = __wmargin;
273  return __old;
274}
275
276/* Return the column number of the current output point in __FS.  */
277ARGP_FS_EI size_t
278__argp_fmtstream_point (argp_fmtstream_t __fs)
279{
280  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
281    __argp_fmtstream_update (__fs);
282  return __fs->point_col >= 0 ? __fs->point_col : 0;
283}
284
285#if !_LIBC
286#undef __argp_fmtstream_putc
287#undef __argp_fmtstream_puts
288#undef __argp_fmtstream_write
289#undef __argp_fmtstream_set_lmargin
290#undef __argp_fmtstream_set_rmargin
291#undef __argp_fmtstream_set_wmargin
292#undef __argp_fmtstream_point
293#undef __argp_fmtstream_update
294#undef __argp_fmtstream_ensure
295#endif
296
297#endif /* __OPTIMIZE__ */
298
299#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */
300
301#endif /* argp-fmtstream.h */
302