/*** *fwrite.c - read from a stream * * Copyright (c) 1989-1992, 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. * *******************************************************************************/ #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 MTHREAD /* define locking/unlocking version */ size_t _CALLTYPE1 fwrite ( const 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 = _fwrite_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 _fwrite_lk ( #else size_t _CALLTYPE1 fwrite ( #endif const void *buffer, size_t size, size_t num, FILE *stream ) { const char *data; /* point to where data comes from next */ unsigned total; /* total bytes to write */ unsigned 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 (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 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) ? 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 = count - count % bufsize; #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; }