Home | History | Annotate | Download | only in stdio
      1 /*	$OpenBSD: fread.c,v 1.6 2005/08/08 08:05:36 espie Exp $ */
      2 /*-
      3  * Copyright (c) 1990, 1993
      4  *	The Regents of the University of California.  All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * Chris Torek.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #include <stdio.h>
     35 #include <string.h>
     36 #include <errno.h>
     37 #include "local.h"
     38 
     39 static int
     40 lflush(FILE *fp)
     41 {
     42     if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
     43         return (__sflush_locked(fp));
     44     return (0);
     45 }
     46 
     47 size_t
     48 fread(void *buf, size_t size, size_t count, FILE *fp)
     49 {
     50     size_t resid;
     51     char *p;
     52     int r;
     53     size_t total;
     54 
     55     /*
     56      * The ANSI standard requires a return value of 0 for a count
     57      * or a size of 0.  Peculiarily, it imposes no such requirements
     58      * on fwrite; it only requires fread to be broken.
     59      */
     60     if ((resid = count * size) == 0)
     61         return (0);
     62     FLOCKFILE(fp);
     63     if (fp->_r < 0)
     64         fp->_r = 0;
     65     total = resid;
     66     p = buf;
     67 
     68 #if 1  /* BIONIC: optimize unbuffered reads */
     69     if (fp->_flags & __SNBF && fp->_ur == 0)
     70     {
     71         /* the following comes mainly from __srefill(), with slight
     72          * modifications
     73          */
     74 
     75         /* make sure stdio is set up */
     76         if (!__sdidinit)
     77             __sinit();
     78 
     79         fp->_r = 0;     /* largely a convenience for callers */
     80 
     81         /* SysV does not make this test; take it out for compatibility */
     82         if (fp->_flags & __SEOF) {
     83             FUNLOCKFILE(fp);
     84             return (EOF);
     85         }
     86 
     87         /* if not already reading, have to be reading and writing */
     88         if ((fp->_flags & __SRD) == 0) {
     89             if ((fp->_flags & __SRW) == 0) {
     90                 fp->_flags |= __SERR;
     91                 FUNLOCKFILE(fp);
     92                 errno = EBADF;
     93                 return (EOF);
     94             }
     95             /* switch to reading */
     96             if (fp->_flags & __SWR) {
     97                 if (__sflush(fp)) {
     98                     FUNLOCKFILE(fp);
     99                     return (EOF);
    100                 }
    101                 fp->_flags &= ~__SWR;
    102                 fp->_w = 0;
    103                 fp->_lbfsize = 0;
    104             }
    105             fp->_flags |= __SRD;
    106         } else {
    107             /*
    108              * We were reading.  If there is an ungetc buffer,
    109              * we must have been reading from that.  Drop it,
    110              * restoring the previous buffer (if any).  If there
    111              * is anything in that buffer, return.
    112              */
    113             if (HASUB(fp)) {
    114                 FREEUB(fp);
    115             }
    116         }
    117 
    118         /*
    119          * Before reading from a line buffered or unbuffered file,
    120          * flush all line buffered output files, per the ANSI C
    121          * standard.
    122          */
    123 
    124         if (fp->_flags & (__SLBF|__SNBF)) {
    125             /* Ignore this file in _fwalk to deadlock. */
    126             fp->_flags |= __SIGN;
    127             (void) _fwalk(lflush);
    128             fp->_flags &= ~__SIGN;
    129 
    130             /* Now flush this file without locking it. */
    131             if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
    132                 __sflush(fp);
    133         }
    134 
    135         while (resid > 0) {
    136             int   len = (*fp->_read)(fp->_cookie, p, resid );
    137             fp->_flags &= ~__SMOD;
    138             if (len <= 0) {
    139                 if (len == 0)
    140                     fp->_flags |= __SEOF;
    141                 else {
    142                     fp->_flags |= __SERR;
    143                 }
    144                 FUNLOCKFILE(fp);
    145                 return ((total - resid) / size);
    146             }
    147             p     += len;
    148             resid -= len;
    149         }
    150         FUNLOCKFILE(fp);
    151         return (count);
    152     }
    153     else
    154 #endif
    155     {
    156         while (resid > (size_t)(r = fp->_r)) {
    157             (void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
    158             fp->_p += r;
    159             /* fp->_r = 0 ... done in __srefill */
    160             p += r;
    161             resid -= r;
    162             if (__srefill(fp)) {
    163                 /* no more input: return partial result */
    164                 FUNLOCKFILE(fp);
    165                 return ((total - resid) / size);
    166             }
    167         }
    168     }
    169 
    170     (void)memcpy((void *)p, (void *)fp->_p, resid);
    171     fp->_r -= resid;
    172     fp->_p += resid;
    173     FUNLOCKFILE(fp);
    174     return (count);
    175 }
    176