/*** *fwrite.c - read from a stream * * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved. * *Purpose: * Write to the specified stream from the user's buffer. * *Revision History: * 06-23-89 PHG Module created, based on asm version * 01-18-90 GJF Must call _fflush_lk() rather than fflush(). * 02-15-90 GJF _iob[], _iob2[] merge. Also, fixed copyright and * indents. * 03-19-90 GJF Made calling type _CALLTYPE1 and added #include * . Also, fixed compiler warning. * 05-29-90 SBM Use _flush, not [_]fflush[_lk] * 07-26-90 SBM Added #include * 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. * 08-26-92 GJF Include unistd.h for POSIX build. * 04-06-93 SKS Replace _CRTAPI* with __cdecl * 05-11-93 GJF Replaced BUFSIZ with _INTERNAL_BUFSIZ. * 10-22-93 GJF Fix divide-by-0 error in unbuffered case. Also, * replaced MTHREAD with _MT. * 12-30-94 GJF _MAC_ merge. * 03-07-95 GJF _[un]lock_str macros now take FILE * arg. * 05-24-95 CFW Return 0 if none to write. * 03-02-98 GJF Exception-safe locking. * 01-04-99 GJF Changes for 64-bit size_t. * 05-17-99 PML Remove all Macintosh support. * *******************************************************************************/ #include #ifdef _POSIX_ #include #endif #include #include #include #include #include #include /*** *size_t fwrite(void *buffer, size_t size, size_t count, FILE *stream) - * write to the specified stream from the specified buffer. * *Purpose: * Write 'count' items of size 'size' to the specified stream from * the specified buffer. Return when 'count' items have been written * or no more items can be written to the stream. * *Entry: * buffer - pointer to user's buffer * size - size of the item to write * count - number of items to write * stream - stream to write to * *Exit: * Returns the number of (whole) items that were written to the stream. * 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: * fwrite will attempt to buffer the stream (side effect of the _flsbuf * call) if necessary. * * No more than 0xFFFE bytes may be written out at a time by a call to * write(). Further, write() does not handle huge buffers. Therefore, * in large data models, the write request is broken down into chunks * that do not violate these considerations. Each of these chunks is * processed much like an fwrite() call in a small data model (by a * call to _nfwrite()). * * This code depends on _iob[] being a near array. * * MTHREAD/DLL - Handled in just two layers since it is small data * model. The outer layer, fwrite(), handles stream locking/unlocking * and calls _fwrite_lk() to do the work. _fwrite_lk() is the same as * the single-thread, small data model version of fwrite(). * *******************************************************************************/ #ifdef _MT /* define locking/unlocking version */ size_t __cdecl fwrite ( const void *buffer, size_t size, size_t count, FILE *stream ) { size_t retval; _lock_str(stream); /* lock stream */ __try { /* do the read */ retval = _fwrite_lk(buffer, size, count, stream); } __finally { _unlock_str(stream); /* unlock stream */ } return retval; } #endif /* define the normal version */ #ifdef _MT size_t __cdecl _fwrite_lk ( #else size_t __cdecl fwrite ( #endif const void *buffer, size_t size, size_t num, FILE *stream ) { const char *data; /* point to where data comes from next */ size_t total; /* total bytes to write */ size_t count; /* num bytes left to write */ unsigned bufsize; /* size of stream buffer */ unsigned nbytes; /* number of bytes to write now */ unsigned nwritten; /* number of bytes written */ int c; /* a temp char */ /* initialize local vars */ data = buffer; count = total = size * num; if (0 == count) return 0; if (anybuf(stream)) /* already has buffer, use its size */ bufsize = stream->_bufsiz; else /* assume will get _INTERNAL_BUFSIZ buffer */ bufsize = _INTERNAL_BUFSIZ; /* here is the main loop -- we go through here until we're done */ while (count != 0) { /* if the buffer is big and has room, copy data to buffer */ if (bigbuf(stream) && stream->_cnt != 0) { /* how much do we want? */ nbytes = (count < (unsigned)stream->_cnt) ? (unsigned)count : stream->_cnt; memcpy(stream->_ptr, data, nbytes); /* update stream and amt of data written */ count -= nbytes; stream->_cnt -= nbytes; stream->_ptr += nbytes; data += nbytes; } else if (count >= bufsize) { /* If we have more than bufsize chars to write, write data by calling write with an integral number of bufsiz blocks. If we reach here and we have a big buffer, it must be full so _flush it. */ if (bigbuf(stream)) { if (_flush(stream)) { /* error, stream flags set -- we're out of here */ return (total - count) / size; } } /* calc chars to read -- (count/bufsize) * bufsize */ nbytes = ( bufsize ? (unsigned)(count - count % bufsize) : (unsigned)count ); #ifdef _POSIX_ nwritten = write(fileno(stream), data, nbytes); #else nwritten = _write(_fileno(stream), data, nbytes); #endif if (nwritten == (unsigned)EOF) { /* error -- out of here */ stream->_flag |= _IOERR; return (total - count) / size; } /* update count and data to reflect write */ count -= nwritten; data += nwritten; if (nwritten < nbytes) { /* error -- out of here */ stream->_flag |= _IOERR; return (total - count) / size; } } else { /* buffer full and not enough chars to do direct write, so do a _flsbuf. */ c = *data; /* _flsbuf write one char, this is it */ if (_flsbuf(c, stream) == EOF) { /* error or eof, stream flags set by _flsbuf */ return (total - count) / size; } /* _flsbuf wrote a char -- update count */ ++data; --count; /* update buffer size */ bufsize = stream->_bufsiz > 0 ? stream->_bufsiz : 1; } } /* we finished successfully, so just return num */ return num; }