2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENSE file which can be found at the top level of
12 * the sendmail distribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
18 SM_RCSID("@(#)$Id: fvwrite.c,v 1.47 2001/08/27 13:02:20 ca Exp $")
26 #include <sm/setjmp.h>
32 ** SM_FVWRITE -- write memory regions and buffer for file pointer
35 ** fp -- the file pointer to write to
36 ** timeout -- time length for function to return by
37 ** uio -- the memory regions to write
40 ** Failure: returns SM_IO_EOF and sets errno
41 ** Success: returns 0 (zero)
43 ** This routine is large and unsightly, but most of the ugliness due
44 ** to the different kinds of output buffering handled here.
47 #define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n))
48 #define GETIOV(extra_work) \
58 sm_fvwrite(fp
, timeout
, uio
)
59 register SM_FILE_T
*fp
;
61 register struct sm_uio
*uio
;
65 register struct sm_iov
*iov
;
72 if (uio
->uio_resid
== 0)
75 /* make sure we can write */
82 SM_CONVERT_TIME(fp
, fd
, timeout
, &to
);
88 if (fp
->f_flags
& SMNBF
)
90 /* Unbuffered: write up to BUFSIZ bytes at a time. */
94 errno
= 0; /* needed to ensure EOF correctly found */
95 w
= (*fp
->f_write
)(fp
, p
, SM_MIN(len
, SM_IO_BUFSIZ
));
98 if (w
== 0 && errno
== 0)
99 break; /* EOF found */
100 if (IS_IO_ERROR(fd
, w
, timeout
))
101 goto err
; /* errno set */
103 /* write would block */
104 SM_IO_WR_TIMEOUT(fp
, fd
, timeout
);
112 } while ((uio
->uio_resid
-= w
) != 0);
114 else if ((fp
->f_flags
& SMLBF
) == 0)
117 ** Not SMLBF (line-buffered). Either SMFBF or SMNOW
118 ** buffered: fill partially full buffer, if any,
119 ** and then flush. If there is no partial buffer, write
120 ** one bf._size byte chunk directly (without copying).
122 ** String output is a special case: write as many bytes
123 ** as fit, but pretend we wrote everything. This makes
124 ** snprintf() return the number of bytes needed, rather
125 ** than the number used, and avoids its write function
126 ** (so that the write function can be invalid).
132 if ((((fp
->f_flags
& (SMALC
| SMSTR
)) == (SMALC
| SMSTR
))
133 || ((fp
->f_flags
& SMNOW
) != 0))
134 && (size_t) fp
->f_w
< len
)
136 size_t blen
= fp
->f_p
- fp
->f_bf
.smb_base
;
137 unsigned char *tbase
;
140 /* Allocate space exponentially. */
141 tsize
= fp
->f_bf
.smb_size
;
144 tsize
= (tsize
<< 1) + 1;
145 } while ((size_t) tsize
< blen
+ len
);
146 tbase
= (unsigned char *) sm_realloc(fp
->f_bf
.smb_base
,
151 goto err
; /* errno set */
153 fp
->f_w
+= tsize
- fp
->f_bf
.smb_size
;
154 fp
->f_bf
.smb_base
= tbase
;
155 fp
->f_bf
.smb_size
= tsize
;
156 fp
->f_p
= tbase
+ blen
;
159 errno
= 0; /* needed to ensure EOF correctly found */
160 if (fp
->f_flags
& SMSTR
)
162 if (len
< (size_t) w
)
164 COPY(w
); /* copy SM_MIN(fp->f_w,len), */
167 w
= len
; /* but pretend copied all */
169 else if (fp
->f_p
> fp
->f_bf
.smb_base
175 if (sm_flush(fp
, &timeout
))
176 goto err
; /* errno set */
178 else if (len
>= (size_t) (w
= fp
->f_bf
.smb_size
))
181 w
= (*fp
->f_write
)(fp
, p
, w
);
184 if (w
== 0 && errno
== 0)
185 break; /* EOF found */
186 if (IS_IO_ERROR(fd
, w
, timeout
))
187 goto err
; /* errno set */
189 /* write would block */
190 SM_IO_WR_TIMEOUT(fp
, fd
, timeout
);
204 } while ((uio
->uio_resid
-= w
) != 0);
206 if ((fp
->f_flags
& SMNOW
) != 0 && sm_flush(fp
, &timeout
))
207 goto err
; /* errno set */
212 ** Line buffered: like fully buffered, but we
213 ** must check for newlines. Compute the distance
214 ** to the first newline (including the newline),
215 ** or `infinity' if there is none, then pretend
216 ** that the amount to write is SM_MIN(len,nldist).
220 nldist
= 0; /* XXX just to keep gcc happy */
226 nl
= memchr((void *)p
, '\n', len
);
227 nldist
= nl
!= NULL
? nl
+ 1 - p
: len
+ 1;
230 s
= SM_MIN(len
, ((size_t) nldist
));
231 w
= fp
->f_w
+ fp
->f_bf
.smb_size
;
232 errno
= 0; /* needed to ensure EOF correctly found */
233 if (fp
->f_p
> fp
->f_bf
.smb_base
&& s
> w
)
238 if (sm_flush(fp
, &timeout
))
239 goto err
; /* errno set */
241 else if (s
>= (w
= fp
->f_bf
.smb_size
))
243 w
= (*fp
->f_write
)(fp
, p
, w
);
246 if (w
== 0 && errno
== 0)
247 break; /* EOF found */
248 if (IS_IO_ERROR(fd
, w
, timeout
))
249 goto err
; /* errno set */
251 /* write would block */
252 SM_IO_WR_TIMEOUT(fp
, fd
, timeout
);
263 if ((nldist
-= w
) == 0)
265 /* copied the newline: flush and forget */
266 if (sm_flush(fp
, &timeout
))
267 goto err
; /* errno set */
272 } while ((uio
->uio_resid
-= w
) != 0);
278 /* errno set before goto places us here */
279 fp
->f_flags
|= SMERR
;