1 // 2 // _file.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Defines the _iob array, the global __piob pointer, the stdio initialization 7 // and termination code, and the stream locking routines. 8 // 9 #include <corecrt_internal_stdio.h> 10 11 12 13 // FILE descriptors for stdin, stdout, and stderr 14 extern "C" { __crt_stdio_stream_data _iob[_IOB_ENTRIES] = 15 { 16 // ptr _base, _cnt, _flag, _file, _charbuf, _bufsiz 17 { nullptr, nullptr, 0, _IOALLOCATED | _IOREAD, 0, 0, 0}, // stdin 18 { nullptr, nullptr, 0, _IOALLOCATED | _IOWRITE, 1, 0, 0}, // stdout 19 { nullptr, nullptr, 0, _IOALLOCATED | _IOWRITE, 2, 0, 0}, // stderr 20 }; } 21 22 extern "C" FILE* __cdecl __acrt_iob_func(unsigned const id) 23 { 24 return &_iob[id]._public_file; 25 } 26 27 28 29 // Pointer to the array of FILE objects: 30 __crt_stdio_stream_data** __piob; 31 32 33 34 // Number of open streams (set to _NSTREAM by default): 35 #ifdef CRTDLL 36 extern "C" { int _nstream = _NSTREAM_; } 37 #else 38 extern "C" { int _nstream; } 39 #endif 40 41 42 43 // Initializer and terminator for the stdio library: 44 _CRT_LINKER_FORCE_INCLUDE(__acrt_stdio_initializer); 45 _CRT_LINKER_FORCE_INCLUDE(__acrt_stdio_terminator); 46 47 48 49 #ifndef CRTDLL 50 // This variable is used by the statically linked CRT to ensure that if any 51 // stdio functionality is used, the terminate_stdio() function will be 52 // registered for call during CRT termination. 53 extern "C" { int _cflush = 0; } 54 #endif 55 56 57 58 // Initializes the stdio library. Returns 0 on success; -1 on failure. 59 extern "C" int __cdecl __acrt_initialize_stdio() 60 { 61 #ifndef CRTDLL 62 // If the user has not supplied a definition of _nstream, set it to _NSTREAM_. 63 // If the user has supplied a value that is too small, set _nstream to the 64 // minimum acceptable value (_IOB_ENTRIES): 65 if (_nstream == 0) 66 { 67 _nstream = _NSTREAM_; 68 } 69 else if (_nstream < _IOB_ENTRIES) 70 { 71 _nstream = _IOB_ENTRIES; 72 } 73 #endif 74 75 // Allocate the __piob array. Try for _nstream entries first. If this 76 // fails, then reset _nstream to _IOB_ENTRIES an try again. If it still 77 // fails, bail out and cause CRT initialization to fail: 78 __piob = _calloc_crt_t(__crt_stdio_stream_data*, _nstream).detach(); 79 if (!__piob) 80 { 81 _nstream = _IOB_ENTRIES; 82 83 __piob = _calloc_crt_t(__crt_stdio_stream_data*, _nstream).detach(); 84 if (!__piob) 85 { 86 return -1; 87 } 88 } 89 90 // Initialize the first _IOB_ENTRIES to point to the corresponding entries 91 // in _iob[]: 92 for (int i = 0; i != _IOB_ENTRIES; ++i) 93 { 94 __acrt_InitializeCriticalSectionEx(&_iob[i]._lock, _CORECRT_SPINCOUNT, 0); 95 __piob[i] = &_iob[i]; 96 97 // For stdin, stdout, and stderr, we use _NO_CONSOLE_FILENO to allow 98 // callers to distinguish between failure to open a file (-1) and a 99 // program run without a console. 100 intptr_t const os_handle = _osfhnd(i); 101 bool const has_no_console = 102 os_handle == reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE) || 103 os_handle == _NO_CONSOLE_FILENO || 104 os_handle == 0; 105 106 if (has_no_console) 107 { 108 _iob[i]._file = _NO_CONSOLE_FILENO; 109 } 110 } 111 112 return 0; 113 } 114 115 116 117 // Terminates the stdio library. All streams are flushed (this is done even if 118 // we are going to close them since that stream won't do anything to the standard 119 // streams) and closed. 120 extern "C" void __cdecl __acrt_uninitialize_stdio() 121 { 122 _flushall(); 123 _fcloseall(); 124 125 for (int i = 0; i != _IOB_ENTRIES; ++i) 126 { 127 __acrt_stdio_free_buffer_nolock(&__piob[i]->_public_file); 128 DeleteCriticalSection(&__piob[i]->_lock); 129 } 130 131 _free_crt(__piob); 132 __piob = nullptr; 133 } 134 135 136 137 // Locks a stdio stream. 138 extern "C" void __cdecl _lock_file(FILE* const stream) 139 { 140 EnterCriticalSection(&__crt_stdio_stream(stream)->_lock); 141 } 142 143 144 145 // Unlocks a stdio stream. 146 extern "C" void __cdecl _unlock_file(FILE* const stream) 147 { 148 LeaveCriticalSection(&__crt_stdio_stream(stream)->_lock); 149 } 150 151 152 153 extern "C" errno_t __cdecl _get_stream_buffer_pointers( 154 FILE* const public_stream, 155 char*** const base, 156 char*** const ptr, 157 int** const count 158 ) 159 { 160 _VALIDATE_RETURN_ERRCODE(public_stream != nullptr, EINVAL); 161 162 __crt_stdio_stream const stream(public_stream); 163 if (base) 164 { 165 *base = &stream->_base; 166 } 167 168 if (ptr) 169 { 170 *ptr = &stream->_ptr; 171 } 172 173 if (count) 174 { 175 *count = &stream->_cnt; 176 } 177 178 return 0; 179 } 180