summaryrefslogtreecommitdiffstats
path: root/private/crt32/stdio/fread.c
blob: c925264f5b44a0de97348169157abe9d003fe92d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/***
*fread.c - read from a stream
*
*	Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	Read from the specified stream into the user's buffer.
*
*Revision History:
*	06-23-89  PHG	Module created, based on asm version
*	02-15-90  GJF	_iob[], _iob2[] merge. Also, fixed copyright and
*			indents.
*	03-19-90  GJF	Made calling type _CALLTYPE1 and added #include
*			<cruntime.h>.
*	08-14-90  SBM	Compiles cleanly with -W3
*	10-02-90  GJF	New-style function declarators.
*	01-22-91  GJF	ANSI naming.
*	03-27-92  DJM	POSIX support.
*	06-22-92  GJF	Must return 0 if EITHER size-of-item or number-of-
*			item arguments is 0 (TNT Bug #523)
*	08-26-92  GJF	Include unistd.h for POSIX build.
*
*******************************************************************************/

#include <cruntime.h>
#ifdef	_POSIX_
#include <unistd.h>
#endif
#include <stdio.h>
#include <os2dll.h>
#include <io.h>
#include <string.h>
#include <file2.h>

/***
*size_t fread(void *buffer, size_t size, size_t count, FILE *stream) -
*	read from specified stream into the specified buffer.
*
*Purpose:
*	Read 'count' items of size 'size' from the specified stream into
*	the specified buffer. Return when 'count' items have been read in
*	or no more items can be read from the stream.
*
*Entry:
*	buffer	- pointer to user's buffer
*	size	- size of the item to read in
*	count	- number of items to read
*	stream	- stream to read from
*
*Exit:
*	Returns the number of (whole) items that were read into the buffer.
*	This may be less than 'count' if an error or eof occurred. In this
*	case, ferror() or feof() should be used to distinguish between the
*	two conditions.
*
*Notes:
*	fread will attempt to buffer the stream (side effect of the _filbuf
*	call) if necessary.
*
*	No more than 0xFFFE bytes may be read in at a time by a call to
*	read(). Further, read() does not handle huge buffers. Therefore,
*	in large data models, the read request is broken down into chunks
*	that do not violate these considerations. Each of these chunks is
*	processed much like an fread() call in a small data model (by a
*	call to _nfread()).
*
*	MTHREAD/DLL - Handled in three layers. fread() handles the locking
*	and DS saving/loading/restoring (if required) and calls _fread_lk()
*	to do the work. _fread_lk() is the same as the single-thread,
*	large data model version of fread(). It breaks up the read request
*	into digestible chunks and calls _nfread() to do the actual work.
*
*	386/MTHREAD/DLL - Handled in just the two layers since it is small
*	data model. The outer layer, fread(), takes care of the stream locking
*	and calls _fread_lk() to do the actual work. _fread_lk() is the same
*	as the single-thread version of fread().
*
*******************************************************************************/


#ifdef MTHREAD
/* define locking/unlocking version */
size_t _CALLTYPE1 fread (
	void *buffer,
	size_t size,
	size_t count,
	FILE *stream
	)
{
	int index;
	size_t retval;

	index = _iob_index(stream);
	_lock_str(index);				  /* lock stream */
	retval = _fread_lk(buffer, size, count, stream);  /* do the read */
	_unlock_str(index);				  /* unlock stream */
	return retval;
}
#endif

/* define the normal version */
#ifdef MTHREAD
size_t _CALLTYPE1 _fread_lk (
#else
size_t _CALLTYPE1 fread (
#endif
	void *buffer,
	size_t size,
	size_t num,
	FILE *stream
	)
{
	char *data;			/* point to where should be read next */
	unsigned total; 		/* total bytes to read */
	unsigned count; 		/* num bytes left to read */
	unsigned bufsize;		/* size of stream buffer */
	unsigned nbytes;		/* how much to read now */
	unsigned nread; 		/* how much we did read */
	int c;				/* a temp char */

	/* initialize local vars */
	data = buffer;

	if ( (count = total = size * num) == 0 )
		return 0;

	if (anybuf(stream))
		/* already has buffer, use its size */
		bufsize = stream->_bufsiz;
	else
		/* assume will get BUFSIZ buffer */
		bufsize = BUFSIZ;

	/* here is the main loop -- we go through here until we're done */
	while (count != 0) {
		/* if the buffer exists and has characters, copy them to user
		   buffer */
		if (anybuf(stream) && stream->_cnt != 0) {
			/* how much do we want? */
			nbytes = (count < (unsigned)stream->_cnt) ? count : stream->_cnt;
			memcpy(data, stream->_ptr, nbytes);

			/* update stream and amt of data read */
			count -= nbytes;
			stream->_cnt -= nbytes;
			stream->_ptr += nbytes;
			data += nbytes;
		}
		else if (count >= bufsize) {
			/* If we have more than bufsize chars to read, get data
			   by calling read with an integral number of bufsiz
			   blocks.  Note that if the stream is text mode, read
			   will return less chars than we ordered. */

			/* calc chars to read -- (count/bufsize) * bufsize */
			nbytes = count - count % bufsize;

#ifdef _POSIX_
			nread = read(fileno(stream), data, nbytes);
#else
			nread = _read(_fileno(stream), data, nbytes);
#endif
			if (nread == 0) {
				/* end of file -- out of here */
				stream->_flag |= _IOEOF;
				return (total - count) / size;
			}
			else if (nread == (unsigned)-1) {
				/* error -- out of here */
				stream->_flag |= _IOERR;
				return (total - count) / size;
			}

			/* update count and data to reflect read */
			count -= nread;
			data += nread;
		}
		else {
			/* less than bufsize chars to read, so call _filbuf to
			   fill buffer */
			if ((c = _filbuf(stream)) == EOF) {
				/* error or eof, stream flags set by _filbuf */
				return (total - count) / size;
			}

			/* _filbuf returned a char -- store it */
			*data++ = (char) c;
			--count;

			/* update buffer size */
			bufsize = stream->_bufsiz;
		}
	}

	/* we finished successfully, so just return num */
	return num;
}