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
__acrt_iob_func(unsigned const id)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.
__acrt_initialize_stdio()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.
__acrt_uninitialize_stdio()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.
_lock_file(FILE * const 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.
_unlock_file(FILE * const stream)146 extern "C" void __cdecl _unlock_file(FILE* const stream)
147 {
148 LeaveCriticalSection(&__crt_stdio_stream(stream)->_lock);
149 }
150
151
152
_get_stream_buffer_pointers(FILE * const public_stream,char *** const base,char *** const ptr,int ** const count)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