1e2d66cf785440b89caffd123834e4f573ac75a8
[kopensolaris-gnu/glibc.git] / stdio / fread.c
1 /* Copyright (C) 1991 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->__get_limit == stream->__buffer ||
47       stream->__put_limit > stream->__buffer || stream->__pushed_back)
48     {
49       /* This stream has never been seen before.
50          Calling __fillbf will give it a buffer
51          and I/O functions if it needs them.  */
52       int c = __fillbf(stream);
53       if (c == EOF)
54         return 0;
55       *ptr++ = c;
56       if (--to_read == 0)
57         return 1;
58     }
59
60  read_from_buffer:;
61   if (stream->__bufp < stream->__get_limit)
62     {
63       /* First off, empty out the buffer.  */
64       register size_t copy = stream->__get_limit - stream->__bufp;
65       if (copy > to_read)
66         copy = to_read;
67       to_read -= copy;
68       if (copy > 20)
69         memcpy((PTR) ptr, (PTR) stream->__bufp, copy);
70       else
71         {
72           register size_t i;
73           for (i = 0; i < copy; ++i)
74             ptr[i] = stream->__bufp[i];
75         }
76       stream->__bufp += copy;
77       if (to_read == 0)
78         return nmemb;
79       ptr += copy;
80     }
81
82   /* Reading directly into the user's buffer doesn't help when
83      using a user-specified input buffer filling/expanding function,
84      so we don't do it in that case.  */
85   if (to_read >= stream->__bufsize &&
86       stream->__room_funcs.__input == default_func)
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                 stream->__offset += count;
99                 stream->__target += count;
100                 ptr += count;
101               }
102             else if (count == 0)
103               {
104                 stream->__eof = 1;
105                 break;
106               }
107             else
108               {
109                 stream->__error = 1;
110                 break;
111               }
112           }
113       else
114         stream->__eof = 1;
115     }
116   else
117     {
118       int c = __fillbf(stream);
119       if (c == EOF)
120         return (bytes - to_read) / size;
121       *ptr++ = (char) c;
122       --to_read;
123       if (to_read > 0)
124         goto read_from_buffer;
125     }
126
127   return (bytes - to_read) / size;
128 }