Mon Apr 29 02:48:26 1996 Ulrich Drepper <drepper@cygnus.com>
[kopensolaris-gnu/glibc.git] / stdio / fread.c
1 /* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <ansidecl.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <string.h>
23
24
25 #define default_func    __default_room_functions.__input
26
27 /* Read NMEMB chunks of SIZE bytes each from STREAM into P.  */
28 size_t
29 DEFUN(fread, (p, size, nmemb, stream),
30       PTR p AND size_t size AND size_t nmemb AND register FILE *stream)
31 {
32   register char *ptr = (char *) p;
33   register size_t to_read = size * nmemb;
34   size_t bytes = to_read;
35
36   if (!__validfp(stream) || !stream->__mode.__read)
37     {
38       errno = EINVAL;
39       return 0;
40     }
41   if (feof(stream) || ferror(stream))
42     return 0;
43   if (p == NULL || to_read == 0)
44     return 0;
45
46   if (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back)
47     {
48       /* This stream has never been seen before, or it has a character
49          pushed back.  Call __fillbf to deal with those cases.  Life will
50          be simpler after this call.  */
51       int c = __fillbf(stream);
52       if (c == EOF)
53         return 0;
54       *ptr++ = c;
55       if (--to_read == 0)
56         return 1;
57     }
58
59  read_from_buffer:;
60   if (stream->__bufp < stream->__get_limit)
61     {
62       /* First off, empty out the buffer.  */
63       register size_t copy = stream->__get_limit - stream->__bufp;
64       if (copy > to_read)
65         copy = to_read;
66       to_read -= copy;
67       if (copy > 20)
68         memcpy((PTR) ptr, (PTR) stream->__bufp, copy);
69       else
70         {
71           register size_t i;
72           for (i = 0; i < copy; ++i)
73             ptr[i] = stream->__bufp[i];
74         }
75       stream->__bufp += copy;
76       if (to_read == 0)
77         return nmemb;
78       ptr += copy;
79     }
80
81   /* Reading directly into the user's buffer doesn't help when
82      using a user-specified input buffer filling/expanding function,
83      so we don't do it in that case.  */
84   if (to_read >= stream->__bufsize &&
85       stream->__room_funcs.__input == default_func &&
86       stream->__offset == stream->__target)
87     {
88       /* Read directly into the user's buffer.  */
89       if (stream->__io_funcs.__read != NULL)
90         while (to_read > 0)
91           {
92             register int count;
93             count = (*stream->__io_funcs.__read)(stream->__cookie,
94                                                  ptr, to_read);
95             if (count > 0)
96               {
97                 to_read -= count;
98                 if (stream->__offset != -1)
99                   {
100                     stream->__offset += count;
101                     stream->__target += count;
102                   }
103                 ptr += count;
104               }
105             else if (count == 0)
106               {
107                 stream->__eof = 1;
108                 break;
109               }
110             else
111               {
112                 stream->__error = 1;
113                 break;
114               }
115           }
116       else
117         stream->__eof = 1;
118     }
119   else
120     {
121       int c = __fillbf(stream);
122       if (c == EOF)
123         return (bytes - to_read) / size;
124       *ptr++ = (char) c;
125       --to_read;
126       if (to_read > 0)
127         goto read_from_buffer;
128     }
129
130   return (bytes - to_read) / size;
131 }