argp-fmtstream.h 13.9 KB
Newer Older
1
/* Word-wrapping and line-truncating streams.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1997, 2006-2016 Free Software Foundation, Inc.
3 4 5
   This file is part of the GNU C Library.
   Written by Miles Bader <miles@gnu.ai.mit.edu>.

6
   This program is free software: you can redistribute it and/or modify
Paul Eggert's avatar
Paul Eggert committed
7
   it under the terms of the GNU General Public License as published by
8 9
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
10

Paul Eggert's avatar
Paul Eggert committed
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Paul Eggert's avatar
Paul Eggert committed
13 14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
15

16 17
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18

19
/* This package emulates glibc 'line_wrap_stream' semantics for systems that
20 21 22 23 24 25 26 27 28 29 30
   don't have that.  If the system does have it, it is just a wrapper for
   that.  This header file is only used internally while compiling argp, and
   shouldn't be installed.  */

#ifndef _ARGP_FMTSTREAM_H
#define _ARGP_FMTSTREAM_H

#include <stdio.h>
#include <string.h>
#include <unistd.h>

31 32 33
/* The __attribute__ feature is available in gcc versions 2.5 and later.
   The __-protected variants of the attributes 'format' and 'printf' are
   accepted by gcc versions 2.6.4 (effectively 2.7) and later.
34
   We enable _GL_ATTRIBUTE_FORMAT only if these are supported too, because
35 36
   gnulib and libintl do '#define printf __printf__' when they override
   the 'printf' function.  */
37 38 39 40
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
# define _GL_ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec))
#else
# define _GL_ATTRIBUTE_FORMAT(spec) /* empty */
Karl Berry's avatar
Karl Berry committed
41 42
#endif

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#if    (_LIBC - 0 && !defined (USE_IN_LIBIO)) \
    || (defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H))
/* line_wrap_stream is available, so use that.  */
#define ARGP_FMTSTREAM_USE_LINEWRAP
#endif

#ifdef ARGP_FMTSTREAM_USE_LINEWRAP
/* Just be a simple wrapper for line_wrap_stream; the semantics are
   *slightly* different, as line_wrap_stream doesn't actually make a new
   object, it just modifies the given stream (reversibly) to do
   line-wrapping.  Since we control who uses this code, it doesn't matter.  */

#include <linewrap.h>

typedef FILE *argp_fmtstream_t;

#define argp_make_fmtstream line_wrap_stream
#define __argp_make_fmtstream line_wrap_stream
#define argp_fmtstream_free line_unwrap_stream
#define __argp_fmtstream_free line_unwrap_stream

#define __argp_fmtstream_putc(fs,ch) putc(ch,fs)
#define argp_fmtstream_putc(fs,ch) putc(ch,fs)
#define __argp_fmtstream_puts(fs,str) fputs(str,fs)
#define argp_fmtstream_puts(fs,str) fputs(str,fs)
#define __argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
#define argp_fmtstream_write(fs,str,len) fwrite(str,1,len,fs)
#define __argp_fmtstream_printf fprintf
#define argp_fmtstream_printf fprintf

#define __argp_fmtstream_lmargin line_wrap_lmargin
#define argp_fmtstream_lmargin line_wrap_lmargin
#define __argp_fmtstream_set_lmargin line_wrap_set_lmargin
#define argp_fmtstream_set_lmargin line_wrap_set_lmargin
#define __argp_fmtstream_rmargin line_wrap_rmargin
#define argp_fmtstream_rmargin line_wrap_rmargin
#define __argp_fmtstream_set_rmargin line_wrap_set_rmargin
#define argp_fmtstream_set_rmargin line_wrap_set_rmargin
#define __argp_fmtstream_wmargin line_wrap_wmargin
#define argp_fmtstream_wmargin line_wrap_wmargin
#define __argp_fmtstream_set_wmargin line_wrap_set_wmargin
#define argp_fmtstream_set_wmargin line_wrap_set_wmargin
#define __argp_fmtstream_point line_wrap_point
#define argp_fmtstream_point line_wrap_point

#else /* !ARGP_FMTSTREAM_USE_LINEWRAP */
/* Guess we have to define our own version.  */

struct argp_fmtstream
{
93
  FILE *stream;                 /* The stream we're outputting to.  */
94

95 96
  size_t lmargin, rmargin;      /* Left and right margins.  */
  ssize_t wmargin;              /* Margin to wrap to, or -1 to truncate.  */
97 98 99 100 101 102

  /* Point in buffer to which we've processed for wrapping, but not output.  */
  size_t point_offs;
  /* Output column at POINT_OFFS, or -1 meaning 0 but don't add lmargin.  */
  ssize_t point_col;

103 104 105
  char *buf;                    /* Output buffer.  */
  char *p;                      /* Current end of text in BUF. */
  char *end;                    /* Absolute end of BUF.  */
106 107 108 109 110 111 112 113 114 115 116
};

typedef struct argp_fmtstream *argp_fmtstream_t;

/* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines
   written on it with LMARGIN spaces and limits them to RMARGIN columns
   total.  If WMARGIN >= 0, words that extend past RMARGIN are wrapped by
   replacing the whitespace before them with a newline and WMARGIN spaces.
   Otherwise, chars beyond RMARGIN are simply dropped until a newline.
   Returns NULL if there was an error.  */
extern argp_fmtstream_t __argp_make_fmtstream (FILE *__stream,
117 118 119
                                               size_t __lmargin,
                                               size_t __rmargin,
                                               ssize_t __wmargin);
120
extern argp_fmtstream_t argp_make_fmtstream (FILE *__stream,
121 122 123
                                             size_t __lmargin,
                                             size_t __rmargin,
                                             ssize_t __wmargin);
124 125 126 127 128 129

/* Flush __FS to its stream, and free it (but don't close the stream).  */
extern void __argp_fmtstream_free (argp_fmtstream_t __fs);
extern void argp_fmtstream_free (argp_fmtstream_t __fs);

extern ssize_t __argp_fmtstream_printf (argp_fmtstream_t __fs,
130
                                        const char *__fmt, ...)
131
     _GL_ATTRIBUTE_FORMAT ((printf, 2, 3));
132
extern ssize_t argp_fmtstream_printf (argp_fmtstream_t __fs,
133
                                      const char *__fmt, ...)
134
     _GL_ATTRIBUTE_FORMAT ((printf, 2, 3));
135

136
#if _LIBC
137 138 139
extern int __argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch);
extern int argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch);

140 141
extern int __argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str);
extern int argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str);
142 143

extern size_t __argp_fmtstream_write (argp_fmtstream_t __fs,
144
                                      const char *__str, size_t __len);
145
extern size_t argp_fmtstream_write (argp_fmtstream_t __fs,
146
                                    const char *__str, size_t __len);
147
#endif
148 149 150 151 152 153 154 155 156

/* Access macros for various bits of state.  */
#define argp_fmtstream_lmargin(__fs) ((__fs)->lmargin)
#define argp_fmtstream_rmargin(__fs) ((__fs)->rmargin)
#define argp_fmtstream_wmargin(__fs) ((__fs)->wmargin)
#define __argp_fmtstream_lmargin argp_fmtstream_lmargin
#define __argp_fmtstream_rmargin argp_fmtstream_rmargin
#define __argp_fmtstream_wmargin argp_fmtstream_wmargin

157
#if _LIBC
158 159
/* Set __FS's left margin to LMARGIN and return the old value.  */
extern size_t argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
160
                                          size_t __lmargin);
161
extern size_t __argp_fmtstream_set_lmargin (argp_fmtstream_t __fs,
162
                                            size_t __lmargin);
163 164 165

/* Set __FS's right margin to __RMARGIN and return the old value.  */
extern size_t argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
166
                                          size_t __rmargin);
167
extern size_t __argp_fmtstream_set_rmargin (argp_fmtstream_t __fs,
168
                                            size_t __rmargin);
169 170 171

/* Set __FS's wrap margin to __WMARGIN and return the old value.  */
extern size_t argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
172
                                          size_t __wmargin);
173
extern size_t __argp_fmtstream_set_wmargin (argp_fmtstream_t __fs,
174
                                            size_t __wmargin);
175 176 177 178

/* Return the column number of the current output point in __FS.  */
extern size_t argp_fmtstream_point (argp_fmtstream_t __fs);
extern size_t __argp_fmtstream_point (argp_fmtstream_t __fs);
179
#endif
180 181 182 183 184 185 186

/* Internal routines.  */
extern void _argp_fmtstream_update (argp_fmtstream_t __fs);
extern void __argp_fmtstream_update (argp_fmtstream_t __fs);
extern int _argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);
extern int __argp_fmtstream_ensure (argp_fmtstream_t __fs, size_t __amount);

187
#if !_LIBC || defined __OPTIMIZE__
188 189 190 191 192 193 194 195 196 197 198 199
/* Inline versions of above routines.  */

#if !_LIBC
#define __argp_fmtstream_putc argp_fmtstream_putc
#define __argp_fmtstream_puts argp_fmtstream_puts
#define __argp_fmtstream_write argp_fmtstream_write
#define __argp_fmtstream_set_lmargin argp_fmtstream_set_lmargin
#define __argp_fmtstream_set_rmargin argp_fmtstream_set_rmargin
#define __argp_fmtstream_set_wmargin argp_fmtstream_set_wmargin
#define __argp_fmtstream_point argp_fmtstream_point
#define __argp_fmtstream_update _argp_fmtstream_update
#define __argp_fmtstream_ensure _argp_fmtstream_ensure
200 201 202
#ifndef _GL_INLINE_HEADER_BEGIN
 #error "Please include config.h first."
#endif
Paul Eggert's avatar
Paul Eggert committed
203 204 205 206
_GL_INLINE_HEADER_BEGIN
#ifndef ARGP_FS_EI
# define ARGP_FS_EI _GL_INLINE
#endif
207 208 209
#endif

#ifndef ARGP_FS_EI
210 211 212 213 214
# ifdef __GNUC__
   /* GCC 4.3 and above with -std=c99 or -std=gnu99 implements ISO C99
      inline semantics, unless -fgnu89-inline is used.  It defines a macro
      __GNUC_STDC_INLINE__ to indicate this situation or a macro
      __GNUC_GNU_INLINE__ to indicate the opposite situation.
215

216 217 218 219
      GCC 4.2 with -std=c99 or -std=gnu99 implements the GNU C inline
      semantics but warns, unless -fgnu89-inline is used:
        warning: C99 inline functions are not supported; using GNU89
        warning: to disable this warning use -fgnu89-inline or the gnu_inline function attribute
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
      It defines a macro __GNUC_GNU_INLINE__ to indicate this situation.

      Whereas Apple GCC 4.0.1 build 5479 without -std=c99 or -std=gnu99
      implements the GNU C inline semantics and defines the macro
      __GNUC_GNU_INLINE__, but it does not warn and does not support
      __attribute__ ((__gnu_inline__)).

      All in all, these are the possible combinations.  For every compiler,
      we need to choose ARGP_FS_EI so that the corresponding table cell
      contains an "ok".

        \    ARGP_FS_EI                      inline   extern    extern
          \                                           inline    inline
      CC    \                                                   __attribute__
                                                                ((gnu_inline))

      gcc 4.3.0                              error    ok        ok
      gcc 4.3.0 -std=gnu99 -fgnu89-inline    error    ok        ok
      gcc 4.3.0 -std=gnu99                   ok       error     ok

      gcc 4.2.2                              error    ok        ok
      gcc 4.2.2 -std=gnu99 -fgnu89-inline    error    ok        ok
      gcc 4.2.2 -std=gnu99                   error    warning   ok

      gcc 4.1.2                              error    ok        warning
      gcc 4.1.2 -std=gnu99                   error    ok        warning

      Apple gcc 4.0.1                        error    ok        warning
      Apple gcc 4.0.1 -std=gnu99             ok       error     warning
    */
250 251
#  if defined __GNUC_STDC_INLINE__
#   define ARGP_FS_EI inline
252
#  elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)
253 254 255 256
#   define ARGP_FS_EI extern inline __attribute__ ((__gnu_inline__))
#  else
#   define ARGP_FS_EI extern inline
#  endif
257
# else
258 259
   /* With other compilers, assume the ISO C99 meaning of 'inline', if
      the compiler supports 'inline' at all.  */
260 261
#  define ARGP_FS_EI inline
# endif
262 263 264 265
#endif

ARGP_FS_EI size_t
__argp_fmtstream_write (argp_fmtstream_t __fs,
266
                        const char *__str, size_t __len)
267 268 269 270 271 272 273 274 275 276 277 278
{
  if (__fs->p + __len <= __fs->end || __argp_fmtstream_ensure (__fs, __len))
    {
      memcpy (__fs->p, __str, __len);
      __fs->p += __len;
      return __len;
    }
  else
    return 0;
}

ARGP_FS_EI int
279
__argp_fmtstream_puts (argp_fmtstream_t __fs, const char *__str)
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
{
  size_t __len = strlen (__str);
  if (__len)
    {
      size_t __wrote = __argp_fmtstream_write (__fs, __str, __len);
      return __wrote == __len ? 0 : -1;
    }
  else
    return 0;
}

ARGP_FS_EI int
__argp_fmtstream_putc (argp_fmtstream_t __fs, int __ch)
{
  if (__fs->p < __fs->end || __argp_fmtstream_ensure (__fs, 1))
    return *__fs->p++ = __ch;
  else
    return EOF;
}

/* Set __FS's left margin to __LMARGIN and return the old value.  */
ARGP_FS_EI size_t
__argp_fmtstream_set_lmargin (argp_fmtstream_t __fs, size_t __lmargin)
{
  size_t __old;
  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
    __argp_fmtstream_update (__fs);
  __old = __fs->lmargin;
  __fs->lmargin = __lmargin;
  return __old;
}

/* Set __FS's right margin to __RMARGIN and return the old value.  */
ARGP_FS_EI size_t
__argp_fmtstream_set_rmargin (argp_fmtstream_t __fs, size_t __rmargin)
{
  size_t __old;
  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
    __argp_fmtstream_update (__fs);
  __old = __fs->rmargin;
  __fs->rmargin = __rmargin;
  return __old;
}

/* Set FS's wrap margin to __WMARGIN and return the old value.  */
ARGP_FS_EI size_t
__argp_fmtstream_set_wmargin (argp_fmtstream_t __fs, size_t __wmargin)
{
  size_t __old;
  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
    __argp_fmtstream_update (__fs);
  __old = __fs->wmargin;
  __fs->wmargin = __wmargin;
  return __old;
}

/* Return the column number of the current output point in __FS.  */
ARGP_FS_EI size_t
__argp_fmtstream_point (argp_fmtstream_t __fs)
{
  if ((size_t) (__fs->p - __fs->buf) > __fs->point_offs)
    __argp_fmtstream_update (__fs);
  return __fs->point_col >= 0 ? __fs->point_col : 0;
}

#if !_LIBC
#undef __argp_fmtstream_putc
#undef __argp_fmtstream_puts
#undef __argp_fmtstream_write
#undef __argp_fmtstream_set_lmargin
#undef __argp_fmtstream_set_rmargin
#undef __argp_fmtstream_set_wmargin
#undef __argp_fmtstream_point
#undef __argp_fmtstream_update
#undef __argp_fmtstream_ensure
Paul Eggert's avatar
Paul Eggert committed
355
_GL_INLINE_HEADER_END
356 357
#endif

358
#endif /* !_LIBC || __OPTIMIZE__ */
359 360 361 362

#endif /* ARGP_FMTSTREAM_USE_LINEWRAP */

#endif /* argp-fmtstream.h */