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.
16 SM_RCSID("@(#)$Id: fvwrite.c,v 1.49 2001/09/11 04:04:48 gshapiro Exp $")
24 #include <sm/setjmp.h>
30 ** SM_FVWRITE -- write memory regions and buffer for file pointer
33 ** fp -- the file pointer to write to
34 ** timeout -- time length for function to return by
35 ** uio -- the memory regions to write
38 ** Failure: returns SM_IO_EOF and sets errno
39 ** Success: returns 0 (zero)
41 ** This routine is large and unsightly, but most of the ugliness due
42 ** to the different kinds of output buffering handled here.
45 #define COPY(n) (void)memcpy((void *)fp->f_p, (void *)p, (size_t)(n))
46 #define GETIOV(extra_work) \
56 sm_fvwrite(fp
, timeout
, uio
)
57 register SM_FILE_T
*fp
;
59 register struct sm_uio
*uio
;
63 register struct sm_iov
*iov
;
70 if (uio
->uio_resid
== 0)
73 /* make sure we can write */
80 SM_CONVERT_TIME(fp
, fd
, timeout
, &to
);
86 if (fp
->f_flags
& SMNBF
)
88 /* Unbuffered: write up to BUFSIZ bytes at a time. */
92 errno
= 0; /* needed to ensure EOF correctly found */
93 w
= (*fp
->f_write
)(fp
, p
, SM_MIN(len
, SM_IO_BUFSIZ
));
96 if (w
== 0 && errno
== 0)
97 break; /* EOF found */
98 if (IS_IO_ERROR(fd
, w
, timeout
))
99 goto err
; /* errno set */
101 /* write would block */
102 SM_IO_WR_TIMEOUT(fp
, fd
, timeout
);
110 } while ((uio
->uio_resid
-= w
) != 0);
112 else if ((fp
->f_flags
& SMLBF
) == 0)
115 ** Not SMLBF (line-buffered). Either SMFBF or SMNOW
116 ** buffered: fill partially full buffer, if any,
117 ** and then flush. If there is no partial buffer, write
118 ** one bf._size byte chunk directly (without copying).
120 ** String output is a special case: write as many bytes
121 ** as fit, but pretend we wrote everything. This makes
122 ** snprintf() return the number of bytes needed, rather
123 ** than the number used, and avoids its write function
124 ** (so that the write function can be invalid).
130 if ((((fp
->f_flags
& (SMALC
| SMSTR
)) == (SMALC
| SMSTR
))
131 || ((fp
->f_flags
& SMNOW
) != 0))
132 && (size_t) fp
->f_w
< len
)
134 size_t blen
= fp
->f_p
- fp
->f_bf
.smb_base
;
135 unsigned char *tbase
;
138 /* Allocate space exponentially. */
139 tsize
= fp
->f_bf
.smb_size
;
142 tsize
= (tsize
<< 1) + 1;
143 } while ((size_t) tsize
< blen
+ len
);
144 tbase
= (unsigned char *) sm_realloc(fp
->f_bf
.smb_base
,
149 goto err
; /* errno set */
151 fp
->f_w
+= tsize
- fp
->f_bf
.smb_size
;
152 fp
->f_bf
.smb_base
= tbase
;
153 fp
->f_bf
.smb_size
= tsize
;
154 fp
->f_p
= tbase
+ blen
;
157 errno
= 0; /* needed to ensure EOF correctly found */
158 if (fp
->f_flags
& SMSTR
)
160 if (len
< (size_t) w
)
162 COPY(w
); /* copy SM_MIN(fp->f_w,len), */
165 w
= len
; /* but pretend copied all */
167 else if (fp
->f_p
> fp
->f_bf
.smb_base
173 if (sm_flush(fp
, &timeout
))
174 goto err
; /* errno set */
176 else if (len
>= (size_t) (w
= fp
->f_bf
.smb_size
))
179 w
= (*fp
->f_write
)(fp
, p
, w
);
182 if (w
== 0 && errno
== 0)
183 break; /* EOF found */
184 if (IS_IO_ERROR(fd
, w
, timeout
))
185 goto err
; /* errno set */
187 /* write would block */
188 SM_IO_WR_TIMEOUT(fp
, fd
, timeout
);
202 } while ((uio
->uio_resid
-= w
) != 0);
204 if ((fp
->f_flags
& SMNOW
) != 0 && sm_flush(fp
, &timeout
))
205 goto err
; /* errno set */
210 ** Line buffered: like fully buffered, but we
211 ** must check for newlines. Compute the distance
212 ** to the first newline (including the newline),
213 ** or `infinity' if there is none, then pretend
214 ** that the amount to write is SM_MIN(len,nldist).
218 nldist
= 0; /* XXX just to keep gcc happy */
224 nl
= memchr((void *)p
, '\n', len
);
225 nldist
= nl
!= NULL
? nl
+ 1 - p
: len
+ 1;
228 s
= SM_MIN(len
, ((size_t) nldist
));
229 w
= fp
->f_w
+ fp
->f_bf
.smb_size
;
230 errno
= 0; /* needed to ensure EOF correctly found */
231 if (fp
->f_p
> fp
->f_bf
.smb_base
&& s
> w
)
236 if (sm_flush(fp
, &timeout
))
237 goto err
; /* errno set */
239 else if (s
>= (w
= fp
->f_bf
.smb_size
))
241 w
= (*fp
->f_write
)(fp
, p
, w
);
244 if (w
== 0 && errno
== 0)
245 break; /* EOF found */
246 if (IS_IO_ERROR(fd
, w
, timeout
))
247 goto err
; /* errno set */
249 /* write would block */
250 SM_IO_WR_TIMEOUT(fp
, fd
, timeout
);
261 if ((nldist
-= w
) == 0)
263 /* copied the newline: flush and forget */
264 if (sm_flush(fp
, &timeout
))
265 goto err
; /* errno set */
270 } while ((uio
->uio_resid
-= w
) != 0);
276 /* errno set before goto places us here */
277 fp
->f_flags
|= SMERR
;