fvwrite.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* $OpenBSD: fvwrite.c,v 1.17 2009/11/09 00:18:27 kurt Exp $ */
  2. /*-
  3. * Copyright (c) 1990, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * This code is derived from software contributed to Berkeley by
  7. * Chris Torek.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <errno.h>
  37. #include "local.h"
  38. #include "fvwrite.h"
  39. /*
  40. * Write some memory regions. Return zero on success, EOF on error.
  41. *
  42. * This routine is large and unsightly, but most of the ugliness due
  43. * to the three different kinds of output buffering is handled here.
  44. */
  45. int
  46. __sfvwrite(FILE *fp, struct __suio *uio)
  47. {
  48. size_t len;
  49. char *p;
  50. struct __siov *iov;
  51. int w, s;
  52. char *nl;
  53. int nlknown, nldist;
  54. if ((len = uio->uio_resid) == 0)
  55. return (0);
  56. /* make sure we can write */
  57. if (cantwrite(fp)) {
  58. errno = EBADF;
  59. return (EOF);
  60. }
  61. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  62. #define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
  63. iov = uio->uio_iov;
  64. p = iov->iov_base;
  65. len = iov->iov_len;
  66. iov++;
  67. #define GETIOV(extra_work) \
  68. while (len == 0) { \
  69. extra_work; \
  70. p = iov->iov_base; \
  71. len = iov->iov_len; \
  72. iov++; \
  73. }
  74. if (fp->_flags & __SNBF) {
  75. goto err;
  76. #if 0
  77. /*
  78. * Unbuffered: write up to BUFSIZ bytes at a time.
  79. */
  80. do {
  81. GETIOV(;);
  82. w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ));
  83. if (w <= 0)
  84. goto err;
  85. p += w;
  86. len -= w;
  87. } while ((uio->uio_resid -= w) != 0);
  88. #endif
  89. } else if ((fp->_flags & __SLBF) == 0) {
  90. /*
  91. * Fully buffered: fill partially full buffer, if any,
  92. * and then flush. If there is no partial buffer, write
  93. * one _bf._size byte chunk directly (without copying).
  94. *
  95. * String output is a special case: write as many bytes
  96. * as fit, but pretend we wrote everything. This makes
  97. * snprintf() return the number of bytes needed, rather
  98. * than the number used, and avoids its write function
  99. * (so that the write function can be invalid).
  100. */
  101. do {
  102. GETIOV(;);
  103. if ((fp->_flags & (__SALC | __SSTR)) ==
  104. (__SALC | __SSTR) && fp->_w < len) {
  105. size_t blen = fp->_p - fp->_bf._base;
  106. unsigned char *_base;
  107. int _size;
  108. /* Allocate space exponentially. */
  109. _size = fp->_bf._size;
  110. do {
  111. _size = (_size << 1) + 1;
  112. } while (_size < blen + len);
  113. _base = realloc(fp->_bf._base, _size + 1);
  114. if (_base == NULL)
  115. goto err;
  116. fp->_w += _size - fp->_bf._size;
  117. fp->_bf._base = _base;
  118. fp->_bf._size = _size;
  119. fp->_p = _base + blen;
  120. }
  121. w = fp->_w;
  122. if (fp->_flags & __SSTR) {
  123. if (len < w)
  124. w = len;
  125. COPY(w); /* copy MIN(fp->_w,len), */
  126. fp->_w -= w;
  127. fp->_p += w;
  128. w = len; /* but pretend copied all */
  129. } else if (fp->_p > fp->_bf._base && len > w) {
  130. #if 0
  131. /* fill and flush */
  132. COPY(w);
  133. /* fp->_w -= w; */ /* unneeded */
  134. fp->_p += w;
  135. if (__sflush(fp))
  136. #endif
  137. goto err;
  138. } else if (len >= (w = fp->_bf._size)) {
  139. #if 0
  140. /* write directly */
  141. w = (*fp->_write)(fp->_cookie, p, w);
  142. if (w <= 0)
  143. #endif
  144. goto err;
  145. } else {
  146. /* fill and done */
  147. w = len;
  148. COPY(w);
  149. fp->_w -= w;
  150. fp->_p += w;
  151. }
  152. p += w;
  153. len -= w;
  154. } while ((uio->uio_resid -= w) != 0);
  155. } else {
  156. /*
  157. * Line buffered: like fully buffered, but we
  158. * must check for newlines. Compute the distance
  159. * to the first newline (including the newline),
  160. * or `infinity' if there is none, then pretend
  161. * that the amount to write is MIN(len,nldist).
  162. */
  163. nlknown = 0;
  164. nldist = 0; /* XXX just to keep gcc happy */
  165. do {
  166. GETIOV(nlknown = 0);
  167. if (!nlknown) {
  168. nl = memchr((void *)p, '\n', len);
  169. nldist = nl ? nl + 1 - p : len + 1;
  170. nlknown = 1;
  171. }
  172. s = MIN(len, nldist);
  173. w = fp->_w + fp->_bf._size;
  174. if (fp->_p > fp->_bf._base && s > w) {
  175. #if 0
  176. COPY(w);
  177. /* fp->_w -= w; */
  178. fp->_p += w;
  179. if (__sflush(fp))
  180. #endif
  181. goto err;
  182. } else if (s >= (w = fp->_bf._size)) {
  183. #if 0
  184. w = (*fp->_write)(fp->_cookie, p, w);
  185. if (w <= 0)
  186. #endif
  187. goto err;
  188. } else {
  189. w = s;
  190. COPY(w);
  191. fp->_w -= w;
  192. fp->_p += w;
  193. }
  194. if ((nldist -= w) == 0) {
  195. #if 0
  196. /* copied the newline: flush and forget */
  197. if (__sflush(fp))
  198. #endif
  199. goto err;
  200. //nlknown = 0;
  201. }
  202. p += w;
  203. len -= w;
  204. } while ((uio->uio_resid -= w) != 0);
  205. }
  206. return (0);
  207. err:
  208. fp->_flags |= __SERR;
  209. return (EOF);
  210. }