Reactos
at master 118 lines 4.4 kB view raw
1// 2// setvbuf.cpp 3// 4// Copyright (c) Microsoft Corporation. All rights reserved. 5// 6// Defines setvbuf(), which is used to set buffering mode for a stream. 7// 8#include <corecrt_internal_stdio.h> 9#include <corecrt_internal_ptd_propagation.h> 10 11 12 13// Helper for setvbuf() that sets various buffer properties and return zero. 14static int __cdecl set_buffer( 15 __crt_stdio_stream const stream, 16 _In_reads_opt_(buffer_size_in_bytes) char* const buffer, 17 size_t const buffer_size_in_bytes, 18 int const new_flag_bits 19 ) throw() 20{ 21 stream.set_flags(new_flag_bits); 22 stream->_bufsiz = static_cast<int>(buffer_size_in_bytes); 23 stream->_ptr = buffer; 24 stream->_base = buffer; 25 stream->_cnt = 0; 26 27 return 0; 28} 29 30 31 32// Controls buffering and buffer size for the specified stream. The array 33// pointed to by 'buffer' is used as a buffer for the stream. If 'buffer' is 34// null, the CRT allocates a buffer of the requested size. The 'type' specifies 35// the type of buffering, which must be one of _IONBF (no buffering) or _IOLBF 36// or _IOFBF (both of which mean full buffering). 37// 38// Returns zero on success; nonzero on failure. 39static int __cdecl _setvbuf_internal( 40 FILE* const public_stream, 41 char* const buffer, 42 int const type, 43 size_t const buffer_size_in_bytes, 44 __crt_cached_ptd_host& ptd 45 ) 46{ 47 __crt_stdio_stream const stream(public_stream); 48 49 _UCRT_VALIDATE_RETURN(ptd, stream.valid(), EINVAL, -1); 50 51 // Make sure 'type' is one of the three allowed values, and if we are 52 // buffering, make sure the size is between 2 and INT_MAX: 53 _UCRT_VALIDATE_RETURN(ptd, type == _IONBF || type == _IOFBF || type == _IOLBF, EINVAL, -1); 54 55 if (type == _IOFBF || type == _IOLBF) 56 { 57 _UCRT_VALIDATE_RETURN(ptd, 2 <= buffer_size_in_bytes && buffer_size_in_bytes <= INT_MAX, EINVAL, -1); 58 } 59 60 return __acrt_lock_stream_and_call(stream.public_stream(), [&] 61 { 62 // Force the buffer size to be even by masking the low order bit: 63 size_t const usable_buffer_size = buffer_size_in_bytes & ~static_cast<size_t>(1); 64 65 // Flush the current buffer and free it, if it is ours: 66 __acrt_stdio_flush_nolock(stream.public_stream(), ptd); 67 __acrt_stdio_free_buffer_nolock(stream.public_stream()); 68 69 // Clear the stream state bits related to buffering. Most of these 70 // should never be set when setvbuf() is called, but it doesn't cost 71 // anything to be safe. 72 stream.unset_flags(_IOBUFFER_CRT | _IOBUFFER_USER | _IOBUFFER_NONE | 73 _IOBUFFER_SETVBUF | _IOBUFFER_STBUF | _IOCTRLZ); 74 75 // Case 1: No buffering: 76 if (type & _IONBF) 77 { 78 return set_buffer(stream, reinterpret_cast<char*>(&stream->_charbuf), 2, _IOBUFFER_NONE); 79 } 80 81 // Cases 2 and 3 (below) cover the _IOFBF and _IOLBF types of buffering. 82 // Line buffering is treated the same as full buffering, so the _IOLBF 83 // bit in the flag is never set. Finally, since _IOFBF is defined to 84 // be zero, full buffering is simply assumed whenever _IONBF is not set. 85 86 // Case 2: Default buffering, CRT-allocated buffer: 87 if (buffer == nullptr) 88 { 89 char* const crt_buffer = _calloc_crt_t(char, usable_buffer_size).detach(); 90 if (!crt_buffer) 91 { 92 #ifndef CRTDLL 93 // Force library pre-termination procedure (this is placed here 94 // because the code path should almost never be hit): 95 ++_cflush; 96 #endif 97 98 return -1; 99 } 100 101 return set_buffer(stream, crt_buffer, usable_buffer_size, _IOBUFFER_CRT | _IOBUFFER_SETVBUF); 102 } 103 104 // Case 3: Default buffering, user-provided buffer: 105 return set_buffer(stream, buffer, usable_buffer_size, _IOBUFFER_USER | _IOBUFFER_SETVBUF); 106 }); 107} 108 109extern "C" int __cdecl setvbuf( 110 FILE* const public_stream, 111 char* const buffer, 112 int const type, 113 size_t const buffer_size_in_bytes 114 ) 115{ 116 __crt_cached_ptd_host ptd; 117 return _setvbuf_internal(public_stream, buffer, type, buffer_size_in_bytes, ptd); 118}