2 * Copyright (c) 1990 The Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * and/or other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 /* No user fns here. Pesch 15apr92. */
28 #define MIN(a, b) ((a) < (b) ? (a) : (b))
29 #define COPY(n) (void) memmove ((void *) fp->_p, (void *) p, (size_t) (n))
31 #define GETIOV(extra_work) \
41 * Write some memory regions. Return zero on success, EOF on error.
43 * On systems supporting threads, this function *must* be called under
44 * _newlib_flockfile_start locking.
46 * This routine is large and unsightly, but most of the ugliness due
47 * to the three different kinds of output buffering is handled here.
51 __sfvwrite_r (struct _reent
*ptr
,
53 register struct __suio
*uio
)
56 register const char *p
= NULL
;
57 register struct __siov
*iov
;
58 register _READ_WRITE_RETURN_TYPE w
, s
;
62 if ((len
= uio
->uio_resid
) == 0)
65 /* make sure we can write */
66 if (cantwrite (ptr
, fp
))
73 /* This only affects Cygwin, so calling __sputc_r *and* __swputc_r
74 * from here doesn't matter.
76 if (fp
->_flags
& __SCLE
) /* text mode */
78 if (fp
->_flags2
& __SWID
)
85 if (__swputc_r (ptr
, *p
, fp
) == EOF
)
92 while (uio
->uio_resid
> 0);
101 if (__sputc_r (ptr
, *p
, fp
) == EOF
)
108 while (uio
->uio_resid
> 0);
114 if (fp
->_flags
& __SNBF
)
117 * Unbuffered: Split buffer in the largest multiple of BUFSIZ < INT_MAX
118 * as some legacy code may expect int instead of size_t.
123 w
= fp
->_write (ptr
, fp
->_cookie
, p
,
124 MIN (len
, INT_MAX
- INT_MAX
% BUFSIZ
));
130 while ((uio
->uio_resid
-= w
) != 0);
132 else if ((fp
->_flags
& __SLBF
) == 0)
135 * Fully buffered: fill partially full buffer, if any,
136 * and then flush. If there is no partial buffer, write
137 * one _bf._size byte chunk directly (without copying).
139 * String output is a special case: write as many bytes
140 * as fit, but pretend we wrote everything. This makes
141 * snprintf() return the number of bytes needed, rather
142 * than the number used, and avoids its write function
143 * (so that the write function can be invalid). If
144 * we are dealing with the asprintf routines, we will
145 * dynamically increase the buffer size as needed.
151 if (fp
->_flags
& __SSTR
)
153 if (len
>= w
&& fp
->_flags
& (__SMBF
| __SOPT
))
154 { /* must be asprintf family */
156 int curpos
= (fp
->_p
- fp
->_bf
._base
);
157 /* Choose a geometric growth factor to avoid
158 quadratic realloc behavior, but use a rate less
159 than (1+sqrt(5))/2 to accomodate malloc
160 overhead. asprintf EXPECTS us to overallocate, so
161 that it can add a trailing \0 without
162 reallocating. The new allocation should thus be
163 max(prev_size*1.5, curpos+len+1). */
164 int newsize
= fp
->_bf
._size
* 3 / 2;
165 if (newsize
< curpos
+ len
+ 1)
166 newsize
= curpos
+ len
+ 1;
167 if (fp
->_flags
& __SOPT
)
169 /* asnprintf leaves original buffer alone. */
170 str
= (unsigned char *)_malloc_r (ptr
, newsize
);
173 _REENT_ERRNO(ptr
) = ENOMEM
;
176 memcpy (str
, fp
->_bf
._base
, curpos
);
177 fp
->_flags
= (fp
->_flags
& ~__SOPT
) | __SMBF
;
181 str
= (unsigned char *)_realloc_r (ptr
, fp
->_bf
._base
,
185 /* Free buffer which is no longer used and clear
186 __SMBF flag to avoid double free in fclose. */
187 _free_r (ptr
, fp
->_bf
._base
);
188 fp
->_flags
&= ~__SMBF
;
189 /* Ensure correct errno, even if free changed it. */
190 _REENT_ERRNO(ptr
) = ENOMEM
;
195 fp
->_p
= str
+ curpos
;
196 fp
->_bf
._size
= newsize
;
198 fp
->_w
= newsize
- curpos
;
202 COPY (w
); /* copy MIN(fp->_w,len), */
205 w
= len
; /* but pretend copied all */
207 else if (fp
->_p
> fp
->_bf
._base
|| len
< fp
->_bf
._size
)
209 /* pass through the buffer */
214 if (fp
->_w
== 0 && _fflush_r (ptr
, fp
))
220 w
= ((int)MIN (len
, INT_MAX
)) / fp
->_bf
._size
* fp
->_bf
._size
;
221 w
= fp
->_write (ptr
, fp
->_cookie
, p
, w
);
228 while ((uio
->uio_resid
-= w
) != 0);
233 * Line buffered: like fully buffered, but we
234 * must check for newlines. Compute the distance
235 * to the first newline (including the newline),
236 * or `infinity' if there is none, then pretend
237 * that the amount to write is MIN(len,nldist).
243 GETIOV (nlknown
= 0);
246 nl
= memchr ((void *) p
, '\n', len
);
247 nldist
= nl
? nl
+ 1 - p
: len
+ 1;
250 s
= MIN (len
, nldist
);
251 w
= fp
->_w
+ fp
->_bf
._size
;
252 if (fp
->_p
> fp
->_bf
._base
&& s
> w
)
257 if (_fflush_r (ptr
, fp
))
260 else if (s
>= (w
= fp
->_bf
._size
))
262 w
= fp
->_write (ptr
, fp
->_cookie
, p
, w
);
273 if ((nldist
-= w
) == 0)
275 /* copied the newline: flush and forget */
276 if (_fflush_r (ptr
, fp
))
283 while ((uio
->uio_resid
-= w
) != 0);
288 fp
->_flags
|= __SERR
;