Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
8.1 KiB

  1. /***
  2. *fread.c - read from a stream
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Read from the specified stream into the user's buffer.
  8. *
  9. *Revision History:
  10. * 06-23-89 PHG Module created, based on asm version
  11. * 02-15-90 GJF _iob[], _iob2[] merge. Also, fixed copyright and
  12. * indents.
  13. * 03-19-90 GJF Made calling type _CALLTYPE1 and added #include
  14. * <cruntime.h>.
  15. * 08-14-90 SBM Compiles cleanly with -W3
  16. * 10-02-90 GJF New-style function declarators.
  17. * 01-22-91 GJF ANSI naming.
  18. * 03-27-92 DJM POSIX support.
  19. * 06-22-92 GJF Must return 0 if EITHER size-of-item or number-of-
  20. * item arguments is 0 (TNT Bug #523)
  21. * 08-26-92 GJF Include unistd.h for POSIX build.
  22. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  23. * 05-11-93 GJF Replaced BUFSIZ with _INTERNAL_BUFSIZ.
  24. * 10-22-93 GJF Fix divide-by-0 error in unbuffered case. Also,
  25. * replaced MTHREAD with _MT.
  26. * 12-30-94 GJF _MAC_ merge.
  27. * 03-07-95 GJF _[un]lock_str macros now take FILE * arg.
  28. * 03-02-98 GJF Exception-safe locking.
  29. * 01-04-99 GJF Changes for 64-bit size_t.
  30. * 05-17-99 PML Remove all Macintosh support.
  31. *
  32. *******************************************************************************/
  33. #include <cruntime.h>
  34. #ifdef _POSIX_
  35. #include <unistd.h>
  36. #endif
  37. #include <stdio.h>
  38. #include <mtdll.h>
  39. #include <io.h>
  40. #include <string.h>
  41. #include <file2.h>
  42. /***
  43. *size_t fread(void *buffer, size_t size, size_t count, FILE *stream) -
  44. * read from specified stream into the specified buffer.
  45. *
  46. *Purpose:
  47. * Read 'count' items of size 'size' from the specified stream into
  48. * the specified buffer. Return when 'count' items have been read in
  49. * or no more items can be read from the stream.
  50. *
  51. *Entry:
  52. * buffer - pointer to user's buffer
  53. * size - size of the item to read in
  54. * count - number of items to read
  55. * stream - stream to read from
  56. *
  57. *Exit:
  58. * Returns the number of (whole) items that were read into the buffer.
  59. * This may be less than 'count' if an error or eof occurred. In this
  60. * case, ferror() or feof() should be used to distinguish between the
  61. * two conditions.
  62. *
  63. *Notes:
  64. * fread will attempt to buffer the stream (side effect of the _filbuf
  65. * call) if necessary.
  66. *
  67. * No more than 0xFFFE bytes may be read in at a time by a call to
  68. * read(). Further, read() does not handle huge buffers. Therefore,
  69. * in large data models, the read request is broken down into chunks
  70. * that do not violate these considerations. Each of these chunks is
  71. * processed much like an fread() call in a small data model (by a
  72. * call to _nfread()).
  73. *
  74. * MTHREAD/DLL - Handled in three layers. fread() handles the locking
  75. * and DS saving/loading/restoring (if required) and calls _fread_lk()
  76. * to do the work. _fread_lk() is the same as the single-thread,
  77. * large data model version of fread(). It breaks up the read request
  78. * into digestible chunks and calls _nfread() to do the actual work.
  79. *
  80. * 386/MTHREAD/DLL - Handled in just the two layers since it is small
  81. * data model. The outer layer, fread(), takes care of the stream locking
  82. * and calls _fread_lk() to do the actual work. _fread_lk() is the same
  83. * as the single-thread version of fread().
  84. *
  85. *******************************************************************************/
  86. #ifdef _MT
  87. /* define locking/unlocking version */
  88. size_t __cdecl fread (
  89. void *buffer,
  90. size_t size,
  91. size_t count,
  92. FILE *stream
  93. )
  94. {
  95. size_t retval;
  96. _lock_str(stream); /* lock stream */
  97. __try {
  98. /* do the read */
  99. retval = _fread_lk(buffer, size, count, stream);
  100. }
  101. __finally {
  102. _unlock_str(stream); /* unlock stream */
  103. }
  104. return retval;
  105. }
  106. #endif
  107. /* define the normal version */
  108. #ifdef _MT
  109. size_t __cdecl _fread_lk (
  110. #else
  111. size_t __cdecl fread (
  112. #endif
  113. void *buffer,
  114. size_t size,
  115. size_t num,
  116. FILE *stream
  117. )
  118. {
  119. char *data; /* point to where should be read next */
  120. size_t total; /* total bytes to read */
  121. size_t count; /* num bytes left to read */
  122. unsigned bufsize; /* size of stream buffer */
  123. unsigned nbytes; /* how much to read now */
  124. unsigned nread; /* how much we did read */
  125. int c; /* a temp char */
  126. /* initialize local vars */
  127. data = buffer;
  128. if ( (count = total = size * num) == 0 )
  129. return 0;
  130. if (anybuf(stream))
  131. /* already has buffer, use its size */
  132. bufsize = stream->_bufsiz;
  133. else
  134. /* assume will get _INTERNAL_BUFSIZ buffer */
  135. bufsize = _INTERNAL_BUFSIZ;
  136. /* here is the main loop -- we go through here until we're done */
  137. while (count != 0) {
  138. /* if the buffer exists and has characters, copy them to user
  139. buffer */
  140. if (anybuf(stream) && stream->_cnt != 0) {
  141. /* how much do we want? */
  142. nbytes = (count < (size_t)stream->_cnt) ? (unsigned)count : stream->_cnt;
  143. memcpy(data, stream->_ptr, nbytes);
  144. /* update stream and amt of data read */
  145. count -= nbytes;
  146. stream->_cnt -= nbytes;
  147. stream->_ptr += nbytes;
  148. data += nbytes;
  149. }
  150. else if (count >= bufsize) {
  151. /* If we have more than bufsize chars to read, get data
  152. by calling read with an integral number of bufsiz
  153. blocks. Note that if the stream is text mode, read
  154. will return less chars than we ordered. */
  155. /* calc chars to read -- (count/bufsize) * bufsize */
  156. nbytes = ( bufsize ? (unsigned)(count - count % bufsize) :
  157. (unsigned)count );
  158. #ifdef _POSIX_
  159. nread = read(fileno(stream), data, nbytes);
  160. #else
  161. nread = _read(_fileno(stream), data, nbytes);
  162. #endif
  163. if (nread == 0) {
  164. /* end of file -- out of here */
  165. stream->_flag |= _IOEOF;
  166. return (total - count) / size;
  167. }
  168. else if (nread == (unsigned)-1) {
  169. /* error -- out of here */
  170. stream->_flag |= _IOERR;
  171. return (total - count) / size;
  172. }
  173. /* update count and data to reflect read */
  174. count -= nread;
  175. data += nread;
  176. }
  177. else {
  178. /* less than bufsize chars to read, so call _filbuf to
  179. fill buffer */
  180. if ((c = _filbuf(stream)) == EOF) {
  181. /* error or eof, stream flags set by _filbuf */
  182. return (total - count) / size;
  183. }
  184. /* _filbuf returned a char -- store it */
  185. *data++ = (char) c;
  186. --count;
  187. /* update buffer size */
  188. bufsize = stream->_bufsiz;
  189. }
  190. }
  191. /* we finished successfully, so just return num */
  192. return num;
  193. }