home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / fwrite.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  7KB  |  188 lines

  1. /***
  2. *fwrite.c - read from a stream
  3. *
  4. *       Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Write to the specified stream from the user's buffer.
  8. *
  9. *******************************************************************************/
  10.  
  11. #include <cruntime.h>
  12. #include <stdio.h>
  13. #include <mtdll.h>
  14. #include <io.h>
  15. #include <string.h>
  16. #include <file2.h>
  17. #include <internal.h>
  18.  
  19. /***
  20. *size_t fwrite(void *buffer, size_t size, size_t count, FILE *stream) -
  21. *       write to the specified stream from the specified buffer.
  22. *
  23. *Purpose:
  24. *       Write 'count' items of size 'size' to the specified stream from
  25. *       the specified buffer. Return when 'count' items have been written
  26. *       or no more items can be written to the stream.
  27. *
  28. *Entry:
  29. *       buffer  - pointer to user's buffer
  30. *       size    - size of the item to write
  31. *       count   - number of items to write
  32. *       stream  - stream to write to
  33. *
  34. *Exit:
  35. *       Returns the number of (whole) items that were written to the stream.
  36. *       This may be less than 'count' if an error or eof occurred. In this
  37. *       case, ferror() or feof() should be used to distinguish between the
  38. *       two conditions.
  39. *
  40. *Notes:
  41. *       fwrite will attempt to buffer the stream (side effect of the _flsbuf
  42. *       call) if necessary.
  43. *
  44. *       No more than 0xFFFE bytes may be written out at a time by a call to
  45. *       write(). Further, write() does not handle huge buffers. Therefore,
  46. *       in large data models, the write request is broken down into chunks
  47. *       that do not violate these considerations. Each of these chunks is
  48. *       processed much like an fwrite() call in a small data model (by a
  49. *       call to _nfwrite()).
  50. *
  51. *       This code depends on _iob[] being a near array.
  52. *
  53. *       MTHREAD/DLL - Handled in just two layers since it is small data
  54. *       model. The outer layer, fwrite(), handles stream locking/unlocking
  55. *       and calls _fwrite_lk() to do the work. _fwrite_lk() is the same as
  56. *       the single-thread, small data model version of fwrite().
  57. *
  58. *******************************************************************************/
  59.  
  60.  
  61. #ifdef _MT
  62. /* define locking/unlocking version */
  63. size_t __cdecl fwrite (
  64.         const void *buffer,
  65.         size_t size,
  66.         size_t count,
  67.         FILE *stream
  68.         )
  69. {
  70.         size_t retval;
  71.  
  72.         _lock_str(stream);                      /* lock stream */
  73.         retval = _fwrite_lk(buffer, size, count, stream);  /* do the read */
  74.         _unlock_str(stream);                    /* unlock stream */
  75.         return retval;
  76. }
  77. #endif  /* _MT */
  78.  
  79. /* define the normal version */
  80. #ifdef _MT
  81. size_t __cdecl _fwrite_lk (
  82. #else  /* _MT */
  83. size_t __cdecl fwrite (
  84. #endif  /* _MT */
  85.         const void *buffer,
  86.         size_t size,
  87.         size_t num,
  88.         FILE *stream
  89.         )
  90. {
  91.         const char *data;               /* point to where data comes from next */
  92.         unsigned total;                 /* total bytes to write */
  93.         unsigned count;                 /* num bytes left to write */
  94.         unsigned bufsize;               /* size of stream buffer */
  95.         unsigned nbytes;                /* number of bytes to write now */
  96.         unsigned nwritten;              /* number of bytes written */
  97.         int c;                          /* a temp char */
  98.  
  99.         /* initialize local vars */
  100.         data = buffer;
  101.         count = total = size * num;
  102.         if (0 == count)
  103.             return 0;
  104.  
  105.         if (anybuf(stream))
  106.                 /* already has buffer, use its size */
  107.                 bufsize = stream->_bufsiz;
  108.         else
  109. #if defined (_M_M68K) || defined (_M_MPPC)
  110.                 /* assume will get BUFSIZ buffer */
  111.                 bufsize = BUFSIZ;
  112. #else  /* defined (_M_M68K) || defined (_M_MPPC) */
  113.                 /* assume will get _INTERNAL_BUFSIZ buffer */
  114.                 bufsize = _INTERNAL_BUFSIZ;
  115. #endif  /* defined (_M_M68K) || defined (_M_MPPC) */
  116.  
  117.         /* here is the main loop -- we go through here until we're done */
  118.         while (count != 0) {
  119.                 /* if the buffer is big and has room, copy data to buffer */
  120.                 if (bigbuf(stream) && stream->_cnt != 0) {
  121.                         /* how much do we want? */
  122.                         nbytes = (count < (unsigned)stream->_cnt) ? count : stream->_cnt;
  123.                         memcpy(stream->_ptr, data, nbytes);
  124.  
  125.                         /* update stream and amt of data written */
  126.                         count -= nbytes;
  127.                         stream->_cnt -= nbytes;
  128.                         stream->_ptr += nbytes;
  129.                         data += nbytes;
  130.                 }
  131.                 else if (count >= bufsize) {
  132.                         /* If we have more than bufsize chars to write, write
  133.                            data by calling write with an integral number of
  134.                            bufsiz blocks.  If we reach here and we have a big
  135.                            buffer, it must be full so _flush it. */
  136.  
  137.                         if (bigbuf(stream)) {
  138.                                 if (_flush(stream)) {
  139.                                         /* error, stream flags set -- we're out
  140.                                            of here */
  141.                                         return (total - count) / size;
  142.                                 }
  143.                         }
  144.  
  145.                         /* calc chars to read -- (count/bufsize) * bufsize */
  146.                         nbytes = ( bufsize ? (count - count % bufsize) :
  147.                                    count );
  148.  
  149.                         nwritten = _write(_fileno(stream), data, nbytes);
  150.                         if (nwritten == (unsigned)EOF) {
  151.                                 /* error -- out of here */
  152.                                 stream->_flag |= _IOERR;
  153.                                 return (total - count) / size;
  154.                         }
  155.  
  156.                         /* update count and data to reflect write */
  157.  
  158.                         count -= nwritten;
  159.                         data += nwritten;
  160.  
  161.                         if (nwritten < nbytes) {
  162.                                 /* error -- out of here */
  163.                                 stream->_flag |= _IOERR;
  164.                                 return (total - count) / size;
  165.                         }
  166.                 }
  167.                 else {
  168.                         /* buffer full and not enough chars to do direct write,
  169.                            so do a _flsbuf. */
  170.                         c = *data;  /* _flsbuf write one char, this is it */
  171.                         if (_flsbuf(c, stream) == EOF) {
  172.                                 /* error or eof, stream flags set by _flsbuf */
  173.                                 return (total - count) / size;
  174.                         }
  175.  
  176.                         /* _flsbuf wrote a char -- update count */
  177.                         ++data;
  178.                         --count;
  179.  
  180.                         /* update buffer size */
  181.                         bufsize = stream->_bufsiz > 0 ? stream->_bufsiz : 1;
  182.                 }
  183.         }
  184.  
  185.         /* we finished successfully, so just return num */
  186.         return num;
  187. }
  188.