Rev 4874 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * Copyright (c) 1990 The Regents of the University of California. |
||
3 | * All rights reserved. |
||
4 | * |
||
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 | * advertising materials, and 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. |
||
16 | */ |
||
17 | /* No user fns here. Pesch 15apr92. */ |
||
18 | |||
19 | #include <_ansi.h> |
||
20 | #include |
||
21 | #include |
||
22 | #include |
||
23 | #include |
||
4921 | Serge | 24 | #include |
4349 | Serge | 25 | #include "local.h" |
26 | #include "fvwrite.h" |
||
27 | |||
28 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
||
29 | #define COPY(n) _CAST_VOID memmove ((_PTR) fp->_p, (_PTR) p, (size_t) (n)) |
||
30 | |||
31 | #define GETIOV(extra_work) \ |
||
32 | while (len == 0) \ |
||
33 | { \ |
||
34 | extra_work; \ |
||
35 | p = iov->iov_base; \ |
||
36 | len = iov->iov_len; \ |
||
37 | iov++; \ |
||
38 | } |
||
39 | |||
40 | /* |
||
41 | * Write some memory regions. Return zero on success, EOF on error. |
||
42 | * |
||
43 | * This routine is large and unsightly, but most of the ugliness due |
||
44 | * to the three different kinds of output buffering is handled here. |
||
45 | */ |
||
46 | |||
47 | int |
||
48 | _DEFUN(__sfvwrite_r, (ptr, fp, uio), |
||
49 | struct _reent *ptr _AND |
||
50 | register FILE *fp _AND |
||
51 | register struct __suio *uio) |
||
52 | { |
||
53 | register size_t len; |
||
54 | register _CONST char *p = NULL; |
||
55 | register struct __siov *iov; |
||
4921 | Serge | 56 | register _READ_WRITE_RETURN_TYPE w, s; |
4349 | Serge | 57 | char *nl; |
58 | int nlknown, nldist; |
||
59 | |||
60 | if ((len = uio->uio_resid) == 0) |
||
61 | return 0; |
||
62 | |||
63 | /* make sure we can write */ |
||
64 | if (cantwrite (ptr, fp)) |
||
65 | return EOF; |
||
66 | |||
67 | iov = uio->uio_iov; |
||
68 | len = 0; |
||
69 | |||
70 | #ifdef __SCLE |
||
71 | if (fp->_flags & __SCLE) /* text mode */ |
||
72 | { |
||
73 | do |
||
74 | { |
||
75 | GETIOV (;); |
||
76 | while (len > 0) |
||
77 | { |
||
78 | if (putc (*p, fp) == EOF) |
||
79 | return EOF; |
||
80 | p++; |
||
81 | len--; |
||
82 | uio->uio_resid--; |
||
83 | } |
||
84 | } |
||
85 | while (uio->uio_resid > 0); |
||
86 | return 0; |
||
87 | } |
||
88 | #endif |
||
89 | |||
90 | if (fp->_flags & __SNBF) |
||
91 | { |
||
92 | /* |
||
4921 | Serge | 93 | * Unbuffered: Split buffer in the largest multiple of BUFSIZ < INT_MAX |
94 | * as some legacy code may expect int instead of size_t. |
||
4349 | Serge | 95 | */ |
96 | do |
||
97 | { |
||
98 | GETIOV (;); |
||
4921 | Serge | 99 | w = fp->_write (ptr, fp->_cookie, p, |
100 | MIN (len, INT_MAX - INT_MAX % BUFSIZ)); |
||
4349 | Serge | 101 | if (w <= 0) |
102 | goto err; |
||
103 | p += w; |
||
104 | len -= w; |
||
105 | } |
||
106 | while ((uio->uio_resid -= w) != 0); |
||
107 | } |
||
108 | else if ((fp->_flags & __SLBF) == 0) |
||
109 | { |
||
110 | /* |
||
111 | * Fully buffered: fill partially full buffer, if any, |
||
112 | * and then flush. If there is no partial buffer, write |
||
113 | * one _bf._size byte chunk directly (without copying). |
||
114 | * |
||
115 | * String output is a special case: write as many bytes |
||
116 | * as fit, but pretend we wrote everything. This makes |
||
117 | * snprintf() return the number of bytes needed, rather |
||
118 | * than the number used, and avoids its write function |
||
119 | * (so that the write function can be invalid). If |
||
120 | * we are dealing with the asprintf routines, we will |
||
121 | * dynamically increase the buffer size as needed. |
||
122 | */ |
||
123 | do |
||
124 | { |
||
125 | GETIOV (;); |
||
126 | w = fp->_w; |
||
127 | if (fp->_flags & __SSTR) |
||
128 | { |
||
129 | if (len >= w && fp->_flags & (__SMBF | __SOPT)) |
||
130 | { /* must be asprintf family */ |
||
131 | unsigned char *str; |
||
132 | int curpos = (fp->_p - fp->_bf._base); |
||
133 | /* Choose a geometric growth factor to avoid |
||
134 | quadratic realloc behavior, but use a rate less |
||
135 | than (1+sqrt(5))/2 to accomodate malloc |
||
136 | overhead. asprintf EXPECTS us to overallocate, so |
||
137 | that it can add a trailing \0 without |
||
138 | reallocating. The new allocation should thus be |
||
139 | max(prev_size*1.5, curpos+len+1). */ |
||
140 | int newsize = fp->_bf._size * 3 / 2; |
||
141 | if (newsize < curpos + len + 1) |
||
142 | newsize = curpos + len + 1; |
||
143 | if (fp->_flags & __SOPT) |
||
144 | { |
||
145 | /* asnprintf leaves original buffer alone. */ |
||
146 | str = (unsigned char *)_malloc_r (ptr, newsize); |
||
147 | if (!str) |
||
148 | { |
||
149 | ptr->_errno = ENOMEM; |
||
150 | goto err; |
||
151 | } |
||
152 | memcpy (str, fp->_bf._base, curpos); |
||
153 | fp->_flags = (fp->_flags & ~__SOPT) | __SMBF; |
||
154 | } |
||
155 | else |
||
156 | { |
||
157 | str = (unsigned char *)_realloc_r (ptr, fp->_bf._base, |
||
158 | newsize); |
||
159 | if (!str) |
||
160 | { |
||
4921 | Serge | 161 | /* Free buffer which is no longer used and clear |
162 | __SMBF flag to avoid double free in fclose. */ |
||
4349 | Serge | 163 | _free_r (ptr, fp->_bf._base); |
4921 | Serge | 164 | fp->_flags &= ~__SMBF; |
4349 | Serge | 165 | /* Ensure correct errno, even if free changed it. */ |
166 | ptr->_errno = ENOMEM; |
||
167 | goto err; |
||
168 | } |
||
169 | } |
||
170 | fp->_bf._base = str; |
||
171 | fp->_p = str + curpos; |
||
172 | fp->_bf._size = newsize; |
||
173 | w = len; |
||
174 | fp->_w = newsize - curpos; |
||
175 | } |
||
176 | if (len < w) |
||
177 | w = len; |
||
178 | COPY (w); /* copy MIN(fp->_w,len), */ |
||
179 | fp->_w -= w; |
||
180 | fp->_p += w; |
||
181 | w = len; /* but pretend copied all */ |
||
182 | } |
||
4921 | Serge | 183 | else if (fp->_p > fp->_bf._base || len < fp->_bf._size) |
4349 | Serge | 184 | { |
4921 | Serge | 185 | /* pass through the buffer */ |
186 | w = MIN (len, w); |
||
4349 | Serge | 187 | COPY (w); |
4921 | Serge | 188 | fp->_w -= w; |
4349 | Serge | 189 | fp->_p += w; |
4921 | Serge | 190 | if (fp->_w == 0 && _fflush_r (ptr, fp)) |
4349 | Serge | 191 | goto err; |
192 | } |
||
4921 | Serge | 193 | else |
4349 | Serge | 194 | { |
195 | /* write directly */ |
||
4921 | Serge | 196 | w = ((int)MIN (len, INT_MAX)) / fp->_bf._size * fp->_bf._size; |
4349 | Serge | 197 | w = fp->_write (ptr, fp->_cookie, p, w); |
198 | if (w <= 0) |
||
199 | goto err; |
||
200 | } |
||
201 | p += w; |
||
202 | len -= w; |
||
203 | } |
||
204 | while ((uio->uio_resid -= w) != 0); |
||
205 | } |
||
206 | else |
||
207 | { |
||
208 | /* |
||
209 | * Line buffered: like fully buffered, but we |
||
210 | * must check for newlines. Compute the distance |
||
211 | * to the first newline (including the newline), |
||
212 | * or `infinity' if there is none, then pretend |
||
213 | * that the amount to write is MIN(len,nldist). |
||
214 | */ |
||
215 | nlknown = 0; |
||
216 | nldist = 0; |
||
217 | do |
||
218 | { |
||
219 | GETIOV (nlknown = 0); |
||
220 | if (!nlknown) |
||
221 | { |
||
222 | nl = memchr ((_PTR) p, '\n', len); |
||
223 | nldist = nl ? nl + 1 - p : len + 1; |
||
224 | nlknown = 1; |
||
225 | } |
||
226 | s = MIN (len, nldist); |
||
227 | w = fp->_w + fp->_bf._size; |
||
228 | if (fp->_p > fp->_bf._base && s > w) |
||
229 | { |
||
230 | COPY (w); |
||
231 | /* fp->_w -= w; */ |
||
232 | fp->_p += w; |
||
233 | if (_fflush_r (ptr, fp)) |
||
234 | goto err; |
||
235 | } |
||
236 | else if (s >= (w = fp->_bf._size)) |
||
237 | { |
||
238 | w = fp->_write (ptr, fp->_cookie, p, w); |
||
239 | if (w <= 0) |
||
240 | goto err; |
||
241 | } |
||
242 | else |
||
243 | { |
||
244 | w = s; |
||
245 | COPY (w); |
||
246 | fp->_w -= w; |
||
247 | fp->_p += w; |
||
248 | } |
||
249 | if ((nldist -= w) == 0) |
||
250 | { |
||
251 | /* copied the newline: flush and forget */ |
||
252 | if (_fflush_r (ptr, fp)) |
||
253 | goto err; |
||
254 | nlknown = 0; |
||
255 | } |
||
256 | p += w; |
||
257 | len -= w; |
||
258 | } |
||
259 | while ((uio->uio_resid -= w) != 0); |
||
260 | } |
||
261 | return 0; |
||
262 | |||
263 | err: |
||
264 | fp->_flags |= __SERR; |
||
265 | return EOF; |
||
266 | }=>=>>>>=>>> |