]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Stdio/fvwrite.c
StdLib: Remove an unnecessary dependency from LibWchar.
[mirror_edk2.git] / StdLib / LibC / Stdio / fvwrite.c
CommitLineData
53e1e5c6 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
2aa62f2b 10\r
2aa62f2b 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
53e1e5c6 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
2aa62f2b 44#include <LibConfig.h>\r
45#include <sys/EfiCdefs.h>\r
2aa62f2b 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
62int\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
53e1e5c6 74 if(fp == NULL) {\r
75 errno = EINVAL;\r
76 return (EOF);\r
77 }\r
2aa62f2b 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
9f4b48a1 109 if (w < 0)\r
2aa62f2b 110 goto err;\r
111 p += w;\r
112 len -= w;\r
9f4b48a1 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
2aa62f2b 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
226err:\r
227 fp->_flags |= __SERR;\r
228 return (EOF);\r
229}\r