argp-fmtstream.h 14 KB

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