ReactOS 0.4.16-dev-2491-g3dc6630
stream.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Console Utilities Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Provides basic abstraction wrappers around CRT streams or
5 * Win32 console API I/O functions, to deal with i18n + Unicode
6 * related problems.
7 * COPYRIGHT: Copyright 2017-2018 ReactOS Team
8 * Copyright 2017-2018 Hermes Belusca-Maito
9 */
10
18/*
19 * Enable this define if you want to only use CRT functions to output
20 * UNICODE stream to the console, as in the way explained by
21 * http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
22 */
24// #define USE_CRT
25
26/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
27#define UNICODE
28#define _UNICODE
29
30#ifdef USE_CRT
31#include <fcntl.h>
32#include <io.h>
33#endif /* USE_CRT */
34
35#include <windef.h>
36#include <winbase.h>
37#include <wincon.h> // Console APIs (only if kernel32 support included)
38#include <winnls.h>
39#include <strsafe.h>
40
41#include "conutils.h"
42#include "stream.h"
43#include "stream_private.h"
44
45
46/*
47 * Standard console streams, initialized by
48 * calls to ConStreamInit/ConInitStdStreams.
49 */
50#if 0 // FIXME!
52{
53 {0}, // StdIn
54 {0}, // StdOut
55 {0}, // StdErr
56};
57#else
61#endif
62
63
64/* Stream translation modes */
65#ifdef USE_CRT
66/* Lookup table to convert CON_STREAM_MODE to CRT mode */
67static int ConToCRTMode[] =
68{
69 _O_BINARY, // Binary (untranslated)
70 _O_TEXT, // AnsiText (translated)
71 _O_WTEXT, // WideText (UTF16 with BOM; translated)
72 _O_U16TEXT, // UTF16Text (UTF16 without BOM; translated)
73 _O_U8TEXT, // UTF8Text (UTF8 without BOM; translated)
74};
75
76/*
77 * See http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
78 * and http://archives.miloush.net/michkap/archive/2009/08/14/9869928.html
79 * for more details.
80 */
81
82// NOTE1: May the translated mode be cached somehow?
83// NOTE2: We may also call IsConsoleHandle to directly set the mode to
84// _O_U16TEXT if it's ok??
85// NOTE3: _setmode returns the previous mode, or -1 if failure.
86#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage) \
87do { \
88 fflush((Stream)->fStream); \
89 if ((Mode) < ARRAYSIZE(ConToCRTMode)) \
90 _setmode(_fileno((Stream)->fStream), ConToCRTMode[(Mode)]); \
91 else \
92 _setmode(_fileno((Stream)->fStream), _O_TEXT); /* Default to ANSI text */ \
93} while(0)
94
95#else /* defined(USE_CRT) */
96
97/*
98 * We set Stream->CodePage to INVALID_CP (== -1) to signal that the code page
99 * is either not assigned (if the mode is Binary, WideText, or UTF16Text), or
100 * is not cached (if the mode is AnsiText). In this latter case the code page
101 * is resolved inside ConWrite. Finally, if the mode is UTF8Text, the code page
102 * cache is always set to CP_UTF8.
103 * The code page cache can be reset by an explicit call to CON_STREAM_SET_MODE
104 * (i.e. by calling ConStreamSetMode, or by reinitializing the stream with
105 * ConStreamInit(Ex)).
106 *
107 * NOTE: the reserved values are: 0 (CP_ACP), 1 (CP_OEMCP), 2 (CP_MACCP),
108 * 3 (CP_THREAD_ACP), 42 (CP_SYMBOL), 65000 (CP_UTF7) and 65001 (CP_UTF8).
109 */
110#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage) \
111do { \
112 (Stream)->Mode = (Mode); \
113\
114 if ((Mode) == AnsiText) \
115 (Stream)->CodePage = CacheCodePage; /* Possibly assigned */ \
116 else if ((Mode) == UTF8Text) \
117 (Stream)->CodePage = CP_UTF8; /* Fixed */ \
118 else /* Mode == Binary, WideText, UTF16Text */ \
119 (Stream)->CodePage = INVALID_CP; /* Not assigned (meaningless) */ \
120} while(0)
121
122#endif /* defined(USE_CRT) */
123
124
125BOOL
130 IN UINT CacheCodePage OPTIONAL,
131 // IN CON_READ_FUNC ReadFunc OPTIONAL,
132 IN CON_WRITE_FUNC WriteFunc OPTIONAL)
133{
134 /* Parameters validation */
135 if (!Stream || !Handle || (Mode > UTF8Text))
136 return FALSE;
137
138#ifdef USE_CRT
139
140 Stream->fStream = (FILE*)Handle;
141
142#else
143
145 return FALSE;
146
147 /*
148 * As the user calls us by giving us an existing handle to attach on,
149 * it is not our duty to close it if we are called again. The user
150 * is responsible for having opened those handles, and is responsible
151 * for closing them!
152 */
153#if 0
154 /* Attempt to close the handle of the old stream */
155 if (/* Stream->IsInitialized && */ Stream->hHandle &&
156 Stream->hHandle != INVALID_HANDLE_VALUE)
157 {
158 CloseHandle(Stream->hHandle);
159 }
160#endif
161
162 /* Initialize the stream critical section if not already done */
163 if (!Stream->IsInitialized)
164 {
165 InitializeCriticalSection/*AndSpinCount*/(&Stream->Lock /* , 4000 */);
166 Stream->IsInitialized = TRUE;
167 }
168
169 Stream->hHandle = (HANDLE)Handle;
170 Stream->IsConsole = IsConsoleHandle(Stream->hHandle);
171
172#endif /* defined(USE_CRT) */
173
174 /* Set the correct file translation mode */
175 CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
176
177 /* Use the default 'ConWrite' helper if nothing is specified */
178 Stream->WriteFunc = (WriteFunc ? WriteFunc : ConWrite);
179
180 return TRUE;
181}
182
183BOOL
188 IN UINT CacheCodePage OPTIONAL)
189{
190 return ConStreamInitEx(Stream, Handle, Mode, CacheCodePage, ConWrite);
191}
192
193BOOL
197 IN UINT CacheCodePage OPTIONAL)
198{
199 /* Parameters validation */
200 if (!Stream || (Mode > UTF8Text))
201 return FALSE;
202
203#ifdef USE_CRT
204 if (!Stream->fStream)
205 return FALSE;
206#endif
207
208 /* Set the correct file translation mode */
209 CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
210 return TRUE;
211}
212
213BOOL
216 IN UINT CacheCodePage)
217{
218#ifdef USE_CRT
219// FIXME!
220#warning The ConStreamSetCacheCodePage function does not make much sense with the CRT!
221#else
223
224 /* Parameters validation */
225 if (!Stream)
226 return FALSE;
227
228 /*
229 * Keep the original stream mode but set the correct file code page
230 * (will be reset only if Mode == AnsiText).
231 */
232 Mode = Stream->Mode;
233 CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage);
234#endif
235 return TRUE;
236}
237
238HANDLE
241{
242 /* Parameters validation */
243 if (!Stream)
245
246 /*
247 * See https://support.microsoft.com/kb/99173
248 * for more details.
249 */
250
251#ifdef USE_CRT
252 if (!Stream->fStream)
254
255 return (HANDLE)_get_osfhandle(_fileno(Stream->fStream));
256#else
257 return Stream->hHandle;
258#endif
259}
260
261BOOL
265{
266 /* Parameters validation */
267 if (!Stream)
268 return FALSE;
269
270 /*
271 * See https://support.microsoft.com/kb/99173
272 * for more details.
273 */
274
275#ifdef USE_CRT
276 if (!Stream->fStream)
277 return FALSE;
278
279 int fdOut = _open_osfhandle((intptr_t)Handle, _O_TEXT /* FIXME! */);
280 FILE* fpOut = _fdopen(fdOut, "w");
281 *Stream->fStream = *fpOut;
283
284 return TRUE;
285#else
286 /* Flush the stream and reset its handle */
287 if (Stream->hHandle != INVALID_HANDLE_VALUE)
288 FlushFileBuffers(Stream->hHandle);
289
290 Stream->hHandle = Handle;
291 Stream->IsConsole = IsConsoleHandle(Stream->hHandle);
292
293 // NOTE: Mode reset??
294
295 return TRUE;
296#endif
297}
298
299/* EOF */
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define _O_BINARY
Definition: cabinet.h:51
#define _O_TEXT
Definition: cabinet.h:50
#define CloseHandle
Definition: compat.h:739
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
BOOL WINAPI FlushFileBuffers(IN HANDLE hFile)
Definition: fileinfo.c:25
int CDECL _open_osfhandle(intptr_t handle, int oflags)
Definition: file.c:2711
FILE *CDECL _fdopen(int fd, const char *mode)
Definition: file.c:1847
intptr_t CDECL _get_osfhandle(int fd)
Definition: file.c:2117
int CDECL _fileno(FILE *file)
Definition: file.c:1925
int intptr_t
Definition: corecrt.h:176
#define _O_WTEXT
Definition: fcntl.h:30
#define _O_U8TEXT
Definition: fcntl.h:32
#define _O_U16TEXT
Definition: fcntl.h:31
unsigned int BOOL
Definition: ntddk_ex.h:94
ULONG Handle
Definition: gdb_input.c:15
_In_ ULONG Mode
Definition: hubbusif.h:303
static IStream Stream
Definition: htmldoc.c:1115
unsigned int UINT
Definition: ndis.h:50
INT __stdcall ConWrite(IN PCON_STREAM Stream, IN PCTCH szStr, IN DWORD len)
Definition: outstream.c:84
INT(__stdcall * CON_WRITE_FUNC)(IN PCON_STREAM Stream, IN PCTCH szStr, IN DWORD len)
Definition: outstream.h:47
static const PCON_STREAM StdStreams[]
Definition: redir.c:36
#define IsConsoleHandle(h)
Definition: console.h:14
CON_STREAM csStdErr
Definition: stream.c:60
BOOL ConStreamInitEx(OUT PCON_STREAM Stream, IN PVOID Handle, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL, IN CON_WRITE_FUNC WriteFunc OPTIONAL)
Definition: stream.c:126
BOOL ConStreamSetOSHandle(IN PCON_STREAM Stream, IN HANDLE Handle)
Definition: stream.c:262
BOOL ConStreamSetCacheCodePage(IN PCON_STREAM Stream, IN UINT CacheCodePage)
Definition: stream.c:214
#define CON_STREAM_SET_MODE(Stream, Mode, CacheCodePage)
Definition: stream.c:110
BOOL ConStreamSetMode(IN PCON_STREAM Stream, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL)
Definition: stream.c:194
CON_STREAM csStdIn
Definition: stream.c:58
BOOL ConStreamInit(OUT PCON_STREAM Stream, IN PVOID Handle, IN CON_STREAM_MODE Mode, IN UINT CacheCodePage OPTIONAL)
Definition: stream.c:184
CON_STREAM csStdOut
Definition: stream.c:59
HANDLE ConStreamGetOSHandle(IN PCON_STREAM Stream)
Definition: stream.c:239
Console I/O streams.
@ UTF8Text
Definition: stream.h:50
enum _CON_STREAM_MODE CON_STREAM_MODE
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:687
PVOID HANDLE
Definition: typedefs.h:73
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40