]>
Commit | Line | Data |
---|---|---|
1 | /*\r | |
2 | Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r | |
3 | This program and the accompanying materials are licensed and made available\r | |
4 | under the terms and conditions of the BSD License that accompanies this\r | |
5 | distribution. The full text of the license may be found at\r | |
6 | http://opensource.org/licenses/bsd-license.\r | |
7 | \r | |
8 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r | |
9 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r | |
10 | \r | |
11 | * Copyright (c) 1990, 1993\r | |
12 | * The Regents of the University of California. All rights reserved.\r | |
13 | *\r | |
14 | * This code is derived from software contributed to Berkeley by\r | |
15 | * Chris Torek.\r | |
16 | *\r | |
17 | * Redistribution and use in source and binary forms, with or without\r | |
18 | * modification, are permitted provided that the following conditions\r | |
19 | * are met:\r | |
20 | * 1. Redistributions of source code must retain the above copyright\r | |
21 | * notice, this list of conditions and the following disclaimer.\r | |
22 | * 2. Redistributions in binary form must reproduce the above copyright\r | |
23 | * notice, this list of conditions and the following disclaimer in the\r | |
24 | * documentation and/or other materials provided with the distribution.\r | |
25 | * 3. Neither the name of the University nor the names of its contributors\r | |
26 | * may be used to endorse or promote products derived from this software\r | |
27 | * without specific prior written permission.\r | |
28 | *\r | |
29 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND\r | |
30 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r | |
31 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r | |
32 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\r | |
33 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r | |
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r | |
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r | |
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r | |
37 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r | |
38 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r | |
39 | * SUCH DAMAGE.\r | |
40 | \r | |
41 | NetBSD: fvwrite.c,v 1.16.2.1 2007/05/07 19:49:09 pavel Exp\r | |
42 | fvwrite.c 8.1 (Berkeley) 6/4/93\r | |
43 | */\r | |
44 | #include <LibConfig.h>\r | |
45 | #include <sys/EfiCdefs.h>\r | |
46 | \r | |
47 | #include <assert.h>\r | |
48 | #include <errno.h>\r | |
49 | #include <stdio.h>\r | |
50 | #include <stdlib.h>\r | |
51 | #include <string.h>\r | |
52 | #include "reentrant.h"\r | |
53 | #include "local.h"\r | |
54 | #include "fvwrite.h"\r | |
55 | \r | |
56 | /*\r | |
57 | * Write some memory regions. Return zero on success, EOF on error.\r | |
58 | *\r | |
59 | * This routine is large and unsightly, but most of the ugliness due\r | |
60 | * to the three different kinds of output buffering is handled here.\r | |
61 | */\r | |
62 | int\r | |
63 | __sfvwrite(FILE *fp, struct __suio *uio)\r | |
64 | {\r | |
65 | size_t len;\r | |
66 | char *p;\r | |
67 | struct __siov *iov;\r | |
68 | int w, s;\r | |
69 | char *nl;\r | |
70 | int nlknown, nldist;\r | |
71 | \r | |
72 | _DIAGASSERT(fp != NULL);\r | |
73 | _DIAGASSERT(uio != NULL);\r | |
74 | if(fp == NULL) {\r | |
75 | errno = EINVAL;\r | |
76 | return (EOF);\r | |
77 | }\r | |
78 | \r | |
79 | if ((len = uio->uio_resid) == 0)\r | |
80 | return (0);\r | |
81 | /* make sure we can write */\r | |
82 | if (cantwrite(fp)) {\r | |
83 | errno = EBADF;\r | |
84 | return (EOF);\r | |
85 | }\r | |
86 | \r | |
87 | //#define MIN(a, b) ((a) < (b) ? (a) : (b))\r | |
88 | #define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))\r | |
89 | \r | |
90 | iov = uio->uio_iov;\r | |
91 | p = iov->iov_base;\r | |
92 | len = iov->iov_len;\r | |
93 | iov++;\r | |
94 | #define GETIOV(extra_work) \\r | |
95 | while (len == 0) { \\r | |
96 | extra_work; \\r | |
97 | p = iov->iov_base; \\r | |
98 | len = iov->iov_len; \\r | |
99 | iov++; \\r | |
100 | }\r | |
101 | if (fp->_flags & __SNBF) {\r | |
102 | /*\r | |
103 | * Unbuffered: write up to BUFSIZ bytes at a time.\r | |
104 | */\r | |
105 | do {\r | |
106 | GETIOV(;);\r | |
107 | w = (*fp->_write)(fp->_cookie, p,\r | |
108 | (int)MIN(len, BUFSIZ));\r | |
109 | if (w < 0)\r | |
110 | goto err;\r | |
111 | p += w;\r | |
112 | len -= w;\r | |
113 | } while ((uio->uio_resid -= w) > 0);\r | |
114 | uio->uio_resid = 0; // Just in case it went negative such as when NL is expanded to CR NL\r | |
115 | } else if ((fp->_flags & __SLBF) == 0) {\r | |
116 | /*\r | |
117 | * Fully buffered: fill partially full buffer, if any,\r | |
118 | * and then flush. If there is no partial buffer, write\r | |
119 | * one _bf._size byte chunk directly (without copying).\r | |
120 | *\r | |
121 | * String output is a special case: write as many bytes\r | |
122 | * as fit, but pretend we wrote everything. This makes\r | |
123 | * snprintf() return the number of bytes needed, rather\r | |
124 | * than the number used, and avoids its write function\r | |
125 | * (so that the write function can be invalid).\r | |
126 | */\r | |
127 | do {\r | |
128 | GETIOV(;);\r | |
129 | if ((fp->_flags & (__SALC | __SSTR)) ==\r | |
130 | (__SALC | __SSTR) && fp->_w < (int)len) {\r | |
131 | size_t blen = fp->_p - fp->_bf._base;\r | |
132 | unsigned char *_base;\r | |
133 | int _size;\r | |
134 | \r | |
135 | /* Allocate space exponentially. */\r | |
136 | _size = fp->_bf._size;\r | |
137 | do {\r | |
138 | _size = (_size << 1) + 1;\r | |
139 | } while (_size < (int)(blen + len));\r | |
140 | _base = realloc(fp->_bf._base,\r | |
141 | (size_t)(_size + 1));\r | |
142 | if (_base == NULL)\r | |
143 | goto err;\r | |
144 | fp->_w += _size - fp->_bf._size;\r | |
145 | fp->_bf._base = _base;\r | |
146 | fp->_bf._size = _size;\r | |
147 | fp->_p = _base + blen;\r | |
148 | }\r | |
149 | w = fp->_w;\r | |
150 | if (fp->_flags & __SSTR) {\r | |
151 | if (len < (size_t)w)\r | |
152 | w = (int)len;\r | |
153 | COPY(w); /* copy MIN(fp->_w,len), */\r | |
154 | fp->_w -= w;\r | |
155 | fp->_p += w;\r | |
156 | w = (int)len; /* but pretend copied all */\r | |
157 | } else if (fp->_p > fp->_bf._base && len > (size_t)w) {\r | |
158 | /* fill and flush */\r | |
159 | COPY(w);\r | |
160 | /* fp->_w -= w; */ /* unneeded */\r | |
161 | fp->_p += w;\r | |
162 | if (fflush(fp))\r | |
163 | goto err;\r | |
164 | } else if (len >= (size_t)(w = fp->_bf._size)) {\r | |
165 | /* write directly */\r | |
166 | w = (*fp->_write)(fp->_cookie, p, w);\r | |
167 | if (w <= 0)\r | |
168 | goto err;\r | |
169 | } else {\r | |
170 | /* fill and done */\r | |
171 | w = (int)len;\r | |
172 | COPY(w);\r | |
173 | fp->_w -= w;\r | |
174 | fp->_p += w;\r | |
175 | }\r | |
176 | p += w;\r | |
177 | len -= w;\r | |
178 | } while ((uio->uio_resid -= w) != 0);\r | |
179 | } else {\r | |
180 | /*\r | |
181 | * Line buffered: like fully buffered, but we\r | |
182 | * must check for newlines. Compute the distance\r | |
183 | * to the first newline (including the newline),\r | |
184 | * or `infinity' if there is none, then pretend\r | |
185 | * that the amount to write is MIN(len,nldist).\r | |
186 | */\r | |
187 | nlknown = 0;\r | |
188 | nldist = 0; /* XXX just to keep gcc happy */\r | |
189 | do {\r | |
190 | GETIOV(nlknown = 0);\r | |
191 | if (!nlknown) {\r | |
192 | nl = memchr((void *)p, '\n', len); // Divide the string at the first '\n'\r | |
193 | nldist = (int)(nl ? nl + 1 - p : len + 1);\r | |
194 | nlknown = 1;\r | |
195 | }\r | |
196 | s = (int)(MIN((int)len, nldist));\r | |
197 | w = fp->_w + fp->_bf._size;\r | |
198 | if (fp->_p > fp->_bf._base && s > w) {\r | |
199 | COPY(w);\r | |
200 | /* fp->_w -= w; */\r | |
201 | fp->_p += w;\r | |
202 | if (fflush(fp))\r | |
203 | goto err;\r | |
204 | } else if (s >= (w = fp->_bf._size)) {\r | |
205 | w = (*fp->_write)(fp->_cookie, p, w);\r | |
206 | if (w <= 0)\r | |
207 | goto err;\r | |
208 | } else {\r | |
209 | w = s;\r | |
210 | COPY(w);\r | |
211 | fp->_w -= w;\r | |
212 | fp->_p += w;\r | |
213 | }\r | |
214 | if ((nldist -= w) == 0) {\r | |
215 | /* copied the newline: flush and forget */\r | |
216 | if (fflush(fp))\r | |
217 | goto err;\r | |
218 | nlknown = 0;\r | |
219 | }\r | |
220 | p += w;\r | |
221 | len -= w;\r | |
222 | } while ((uio->uio_resid -= w) != 0);\r | |
223 | }\r | |
224 | return (0);\r | |
225 | \r | |
226 | err:\r | |
227 | fp->_flags |= __SERR;\r | |
228 | return (EOF);\r | |
229 | }\r |