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