|
1 /* FVWRITE.C |
|
2 * |
|
3 * Portions Copyright (c) 1990-2004 Nokia Corporation and/or its subsidiary(-ies). |
|
4 * All rights reserved. |
|
5 */ |
|
6 |
|
7 /* No user fns here. Pesch 15apr92. */ |
|
8 |
|
9 /* |
|
10 * Copyright (c) 1990 The Regents of the University of California. |
|
11 * All rights reserved. |
|
12 * |
|
13 * Redistribution and use in source and binary forms are permitted |
|
14 * provided that the above copyright notice and this paragraph are |
|
15 * duplicated in all such forms and that any documentation, |
|
16 * advertising materials, and other materials related to such |
|
17 * distribution and use acknowledge that the software was developed |
|
18 * by the University of California, Berkeley. The name of the |
|
19 * University may not be used to endorse or promote products derived |
|
20 * from this software without specific prior written permission. |
|
21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
|
22 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
|
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
|
24 */ |
|
25 |
|
26 #include <stdio_r.h> |
|
27 #include <string.h> |
|
28 #include "LOCAL.H" |
|
29 #include "FVWRITE.H" |
|
30 |
|
31 #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
|
32 #define COPY(n) (void) memmove((void *) fp->_p, (void *) p, (size_t) (n)) |
|
33 |
|
34 #define GETIOV(extra_work) \ |
|
35 while (len == 0) \ |
|
36 { \ |
|
37 extra_work; \ |
|
38 p = (const char*)iov->iov_base; \ |
|
39 len = iov->iov_len; \ |
|
40 iov++; \ |
|
41 } |
|
42 |
|
43 /* |
|
44 * Write some memory regions. Return zero on success, EOF on error. |
|
45 * |
|
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. |
|
48 */ |
|
49 |
|
50 int |
|
51 __sfvwrite (register FILE *fp,register struct __suio *uio) |
|
52 { |
|
53 register size_t len; |
|
54 register const char *p; |
|
55 register struct __siov *iov; |
|
56 register int w, s; |
|
57 char *nl; |
|
58 int nlknown, nldist = -1; |
|
59 |
|
60 if ((len = uio->uio_resid) == 0) |
|
61 return 0; |
|
62 |
|
63 /* make sure we can write */ |
|
64 if (cantwrite (fp)) |
|
65 return EOF; |
|
66 |
|
67 iov = uio->uio_iov; |
|
68 len = 0; |
|
69 if (fp->_flags & __SNBF) |
|
70 { |
|
71 /* |
|
72 * Unbuffered: write up to BUFSIZ bytes at a time. |
|
73 */ |
|
74 do |
|
75 { |
|
76 GETIOV (;); |
|
77 w = (*fp->_write) (fp->_cookie, p, MIN (len, BUFSIZ)); |
|
78 if (w <= 0) |
|
79 goto err; |
|
80 p += w; |
|
81 len -= w; |
|
82 } |
|
83 while ((uio->uio_resid -= w) != 0); |
|
84 } |
|
85 else if ((fp->_flags & __SLBF) == 0) |
|
86 { |
|
87 /* |
|
88 * Fully buffered: fill partially full buffer, if any, |
|
89 * and then flush. If there is no partial buffer, write |
|
90 * one _bf._size byte chunk directly (without copying). |
|
91 * |
|
92 * String output is a special case: write as many bytes |
|
93 * as fit, but pretend we wrote everything. This makes |
|
94 * snprintf() return the number of bytes needed, rather |
|
95 * than the number used, and avoids its write function |
|
96 * (so that the write function can be invalid). |
|
97 */ |
|
98 do |
|
99 { |
|
100 GETIOV (;); |
|
101 w = fp->_w; |
|
102 if (fp->_flags & __SSTR) |
|
103 { |
|
104 if ((int)len < w) |
|
105 w = len; |
|
106 COPY (w); /* copy MIN(fp->_w,len), */ |
|
107 fp->_w -= w; |
|
108 fp->_p += w; |
|
109 w = len; /* but pretend copied all */ |
|
110 } |
|
111 else if (fp->_p > fp->_bf._base && (int)len > w) |
|
112 { |
|
113 /* fill and flush */ |
|
114 COPY (w); |
|
115 /* fp->_w -= w; *//* unneeded */ |
|
116 fp->_p += w; |
|
117 if (fflush (fp)) |
|
118 goto err; |
|
119 } |
|
120 else if ((int)len >= (w = fp->_bf._size)) |
|
121 { |
|
122 /* write directly */ |
|
123 w = (*fp->_write) (fp->_cookie, p, w); |
|
124 if (w <= 0) |
|
125 goto err; |
|
126 } |
|
127 else |
|
128 { |
|
129 /* fill and done */ |
|
130 w = len; |
|
131 COPY (w); |
|
132 fp->_w -= w; |
|
133 fp->_p += w; |
|
134 } |
|
135 p += w; |
|
136 len -= w; |
|
137 } |
|
138 while ((uio->uio_resid -= w) != 0); |
|
139 } |
|
140 else |
|
141 { |
|
142 /* |
|
143 * Line buffered: like fully buffered, but we |
|
144 * must check for newlines. Compute the distance |
|
145 * to the first newline (including the newline), |
|
146 * or `infinity' if there is none, then pretend |
|
147 * that the amount to write is MIN(len,nldist). |
|
148 */ |
|
149 nlknown = 0; |
|
150 do |
|
151 { |
|
152 GETIOV (nlknown = 0); |
|
153 if (!nlknown) |
|
154 { |
|
155 nl = (char *)memchr ((void *) p, '\n', len); |
|
156 nldist = nl ? nl + 1 - p : len + 1; |
|
157 nlknown = 1; |
|
158 } |
|
159 s = MIN ((int)len, nldist); |
|
160 w = fp->_w + fp->_bf._size; |
|
161 if (fp->_p > fp->_bf._base && s > w) |
|
162 { |
|
163 COPY (w); |
|
164 /* fp->_w -= w; */ |
|
165 fp->_p += w; |
|
166 if (fflush (fp)) |
|
167 goto err; |
|
168 } |
|
169 else if (s >= (w = fp->_bf._size)) |
|
170 { |
|
171 w = (*fp->_write) (fp->_cookie, p, w); |
|
172 if (w <= 0) |
|
173 goto err; |
|
174 } |
|
175 else |
|
176 { |
|
177 w = s; |
|
178 COPY (w); |
|
179 fp->_w -= w; |
|
180 fp->_p += w; |
|
181 } |
|
182 if ((nldist -= w) == 0) |
|
183 { |
|
184 /* copied the newline: flush and forget */ |
|
185 if (fflush (fp)) |
|
186 goto err; |
|
187 nlknown = 0; |
|
188 } |
|
189 p += w; |
|
190 len -= w; |
|
191 } |
|
192 while ((uio->uio_resid -= w) != 0); |
|
193 } |
|
194 return 0; |
|
195 |
|
196 err: |
|
197 fp->_flags |= __SERR; |
|
198 return EOF; |
|
199 } |