xref: /reactos/sdk/lib/ucrt/stdio/_file.cpp (revision ffd69754)
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