mirror of
https://github.com/reactos/reactos.git
synced 2025-01-22 19:43:55 +08:00
[CONUTILS] Split stream.c into input and output stream modules.
As code grows, this will allow for better maintenance of the console stream code. In particular the input stream module will contain special code for handling TTYs, and this is something not all console programs will need. Having this code in a separate module will allow for the linker to possibly remove this code when it is unused.
This commit is contained in:
parent
7082b621a5
commit
4e697fee2c
@ -1,5 +1,7 @@
|
||||
|
||||
list(APPEND SOURCE
|
||||
# instream.c
|
||||
outstream.c
|
||||
pager.c
|
||||
screen.c
|
||||
stream.c
|
||||
|
@ -1,7 +1,9 @@
|
||||
The ReactOS Console Utilities Library v0.1
|
||||
The ReactOS Console Utilities Library v0.2
|
||||
==========================================
|
||||
|
||||
COPYRIGHT: Under GPLv2, see COPYING in the top level directory.
|
||||
LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
Copyright 2017-2018 Hermes Belusca-Maito
|
||||
CREDITS: Thanks to the many people who originally wrote the code that finally
|
||||
ended up inside this library, with more or less refactoring, or
|
||||
whose code served as a basis for some functions of the library.
|
||||
@ -21,23 +23,22 @@ together with printf-like functionality.
|
||||
CONTENTS
|
||||
~-~-~-~-
|
||||
|
||||
0. 'conutils_base' (utils.c and utils.h): Base set of functions for loading
|
||||
-- Main ConUtils Library --
|
||||
|
||||
0. "BASE" (utils.c and utils.h): Base set of functions for loading
|
||||
string resources and message strings, and handle type identification.
|
||||
|
||||
1. 'conutils_stream' (stream.c and stream.h): Console Stream API (CON_STREAM):
|
||||
1. "STREAM" (stream.c and stream.h, instream.c and instream.h, outstream.c
|
||||
and outstream.h): Console Stream API (CON_STREAM):
|
||||
Stream initialization, basic ConStreamRead/Write. Stream utility functions:
|
||||
ConPuts/Printf, ConResPuts/Printf, ConMsgPuts/Printf.
|
||||
Depends on 'conutils_base'.
|
||||
ConPuts/Printf, ConResPuts/Printf, ConMsgPuts/Printf. Depends on "BASE".
|
||||
|
||||
2. 'conutils_screen' (screen.c and screen.h): Console Screen API (CON_SCREEN):
|
||||
2. "SCREEN" (screen.c and screen.h): Console Screen API (CON_SCREEN):
|
||||
Introduces the notion of console/terminal screen around the streams. Manages
|
||||
console/terminal screen metrics for Win32 consoles and TTYs (serial...).
|
||||
Additional Screen utility functions.
|
||||
Depends on 'conutils_stream', and indirectly on 'conutils_base'.
|
||||
Depends on "STREAM", and indirectly on "BASE".
|
||||
|
||||
3. 'conutils_pager' (pager.c and pager.h): Console Pager API (CON_PAGER):
|
||||
3. "PAGER" (pager.c and pager.h): Console Pager API (CON_PAGER):
|
||||
Implements core console/terminal paging functionality around console screens.
|
||||
Depends on 'conutils_screen' and indirectly on 'conutils_stream' and
|
||||
'conutils_base'.
|
||||
|
||||
4. More to come!
|
||||
Depends on "SCREEN", and indirectly on "STREAM" and "BASE".
|
||||
|
@ -1,25 +1,29 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/conutils.h
|
||||
* PURPOSE: Provides simple abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides simple abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __CONUTILS_H__
|
||||
#define __CONUTILS_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library only supports compilation with _UNICODE defined, at the moment!
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "stream.h"
|
||||
// #include "instream.h"
|
||||
#include "outstream.h"
|
||||
#include "screen.h"
|
||||
#include "pager.h"
|
||||
|
||||
#endif /* __CONUTILS_H__ */
|
||||
|
||||
/* EOF */
|
||||
|
49
sdk/lib/conutils/instream.c
Normal file
49
sdk/lib/conutils/instream.c
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enable this define if you want to only use CRT functions to output
|
||||
* UNICODE stream to the console, as in the way explained by
|
||||
* http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
|
||||
*/
|
||||
/** NOTE: Experimental! Don't use USE_CRT yet because output to console is a bit broken **/
|
||||
// #define USE_CRT
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#ifdef USE_CRT
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#endif /* USE_CRT */
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
#include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
|
||||
#include <wincon.h> // Console APIs (only if kernel32 support included)
|
||||
#include <strsafe.h>
|
||||
|
||||
/* PSEH for SEH Support */
|
||||
#include <pseh/pseh2.h>
|
||||
|
||||
#include "conutils.h"
|
||||
#include "stream.h"
|
||||
#include "stream_private.h"
|
||||
|
||||
|
||||
/*
|
||||
* Console I/O utility API -- Input
|
||||
*/
|
||||
|
||||
/* EOF */
|
46
sdk/lib/conutils/instream.h
Normal file
46
sdk/lib/conutils/instream.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __INSTREAM_H__
|
||||
#define __INSTREAM_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Enable this define if you want to only use CRT functions to output
|
||||
* UNICODE stream to the console, as in the way explained by
|
||||
* http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
|
||||
*/
|
||||
/** NOTE: Experimental! Don't use USE_CRT yet because output to console is a bit broken **/
|
||||
// #define USE_CRT
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Shadow type, implementation-specific
|
||||
typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM;
|
||||
|
||||
/*
|
||||
* Console I/O utility API -- Input
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INSTREAM_H__ */
|
||||
|
||||
/* EOF */
|
762
sdk/lib/conutils/outstream.c
Normal file
762
sdk/lib/conutils/outstream.c
Normal file
@ -0,0 +1,762 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
/*
|
||||
* Enable this define if you want to only use CRT functions to output
|
||||
* UNICODE stream to the console, as in the way explained by
|
||||
* http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
|
||||
*/
|
||||
/** NOTE: Experimental! Don't use USE_CRT yet because output to console is a bit broken **/
|
||||
// #define USE_CRT
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#ifdef USE_CRT
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#endif /* USE_CRT */
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
#include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
|
||||
#include <wincon.h> // Console APIs (only if kernel32 support included)
|
||||
#include <strsafe.h>
|
||||
|
||||
/* PSEH for SEH Support */
|
||||
#include <pseh/pseh2.h>
|
||||
|
||||
#include "conutils.h"
|
||||
#include "stream.h"
|
||||
#include "stream_private.h"
|
||||
|
||||
|
||||
// #define RC_STRING_MAX_SIZE 4096
|
||||
#define CON_RC_STRING_MAX_SIZE 4096
|
||||
// #define MAX_BUFFER_SIZE 4096 // Some programs (wlanconf, shutdown) set it to 5024
|
||||
// #define OUTPUT_BUFFER_SIZE 4096 // Name given in cmd/console.c
|
||||
// MAX_STRING_SIZE // Name given in diskpart
|
||||
|
||||
// #define MAX_MESSAGE_SIZE 512 // See shutdown...
|
||||
|
||||
|
||||
/*
|
||||
* Console I/O utility API -- Output
|
||||
*/
|
||||
|
||||
// NOTE: Should be called with the stream locked.
|
||||
INT
|
||||
__stdcall
|
||||
ConWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len)
|
||||
{
|
||||
#ifndef USE_CRT
|
||||
DWORD TotalLen = len, dwNumBytes = 0;
|
||||
PVOID p;
|
||||
|
||||
// CHAR strOem[CON_RC_STRING_MAX_SIZE]; // Some static buffer...
|
||||
|
||||
/* If we do not write anything, just return */
|
||||
if (!szStr || len == 0)
|
||||
return 0;
|
||||
|
||||
/* Check whether we are writing to a console */
|
||||
// if (IsConsoleHandle(Stream->hHandle))
|
||||
if (Stream->IsConsole)
|
||||
{
|
||||
// TODO: Check if (ConStream->Mode == WideText or UTF16Text) ??
|
||||
|
||||
/*
|
||||
* This code is inspired from _cputws, in particular from the fact that,
|
||||
* according to MSDN: https://msdn.microsoft.com/en-us/library/ms687401(v=vs.85).aspx
|
||||
* the buffer size must be less than 64 KB.
|
||||
*
|
||||
* A similar code can be used for implementing _cputs too.
|
||||
*/
|
||||
|
||||
DWORD cchWrite;
|
||||
TotalLen = len, dwNumBytes = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
cchWrite = min(len, 65535 / sizeof(WCHAR));
|
||||
|
||||
// FIXME: Check return value!
|
||||
WriteConsole(Stream->hHandle, szStr, cchWrite, &dwNumBytes, NULL);
|
||||
|
||||
szStr += cchWrite;
|
||||
len -= cchWrite;
|
||||
}
|
||||
|
||||
return (INT)TotalLen; // FIXME: Really return the number of chars written!
|
||||
}
|
||||
|
||||
/*
|
||||
* We are redirected and writing to a file or pipe instead of the console.
|
||||
* Convert the string from TCHARs to the desired output format, if the two differ.
|
||||
*
|
||||
* Implementation NOTE:
|
||||
* MultiByteToWideChar (resp. WideCharToMultiByte) are equivalent to
|
||||
* OemToCharBuffW (resp. CharToOemBuffW), but the latters uselessly
|
||||
* depend on user32.dll, while MultiByteToWideChar and WideCharToMultiByte
|
||||
* only need kernel32.dll.
|
||||
*/
|
||||
if ((Stream->Mode == WideText) || (Stream->Mode == UTF16Text))
|
||||
{
|
||||
#ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
|
||||
/* Convert from the current process/thread's codepage to UTF-16 */
|
||||
WCHAR *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
|
||||
if (!buffer)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
len = (DWORD)MultiByteToWideChar(CP_THREAD_ACP, // CP_ACP, CP_OEMCP
|
||||
0, szStr, (INT)len, buffer, (INT)len);
|
||||
szStr = (PVOID)buffer;
|
||||
#else
|
||||
/*
|
||||
* Do not perform any conversion since we are already in UTF-16,
|
||||
* that is the same encoding as the stream.
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find any newline character in the buffer,
|
||||
* write the part BEFORE the newline, then write
|
||||
* a carriage-return + newline, and then write
|
||||
* the remaining part of the buffer.
|
||||
*
|
||||
* This fixes output in files and serial console.
|
||||
*/
|
||||
while (len > 0)
|
||||
{
|
||||
/* Loop until we find a \r or \n character */
|
||||
// FIXME: What about the pair \r\n ?
|
||||
p = szStr;
|
||||
while (len > 0 && *(PWCHAR)p != L'\r' && *(PWCHAR)p != L'\n')
|
||||
{
|
||||
/* Advance one character */
|
||||
p = (PVOID)((PWCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Write everything up to \r or \n */
|
||||
dwNumBytes = ((PWCHAR)p - (PWCHAR)szStr) * sizeof(WCHAR);
|
||||
WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
|
||||
|
||||
/* If we hit \r or \n ... */
|
||||
if (len > 0 && (*(PWCHAR)p == L'\r' || *(PWCHAR)p == L'\n'))
|
||||
{
|
||||
/* ... send a carriage-return + newline sequence and skip \r or \n */
|
||||
WriteFile(Stream->hHandle, L"\r\n", 2 * sizeof(WCHAR), &dwNumBytes, NULL);
|
||||
szStr = (PVOID)((PWCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
HeapFree(GetProcessHeap(), 0, buffer);
|
||||
#endif
|
||||
}
|
||||
else if ((Stream->Mode == UTF8Text) || (Stream->Mode == AnsiText))
|
||||
{
|
||||
CHAR *buffer;
|
||||
|
||||
/*
|
||||
* Resolve the codepage cache if it was not assigned yet
|
||||
* (only if the stream is in ANSI mode; in UTF8 mode the
|
||||
* codepage was already set to CP_UTF8).
|
||||
*/
|
||||
if (/*(Stream->Mode == AnsiText) &&*/ (Stream->CodePage == INVALID_CP))
|
||||
Stream->CodePage = GetConsoleOutputCP(); // CP_ACP, CP_OEMCP
|
||||
|
||||
#ifdef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
|
||||
/* Convert from UTF-16 to either UTF-8 or ANSI, using stream codepage */
|
||||
// NOTE: MB_LEN_MAX defined either in limits.h or in stdlib.h .
|
||||
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * MB_LEN_MAX);
|
||||
if (!buffer)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
len = WideCharToMultiByte(Stream->CodePage, 0,
|
||||
szStr, len, buffer, len * MB_LEN_MAX,
|
||||
NULL, NULL);
|
||||
szStr = (PVOID)buffer;
|
||||
#else
|
||||
/*
|
||||
* Convert from the current process/thread's codepage to either
|
||||
* UTF-8 or ANSI, using stream codepage.
|
||||
* We need to perform a double conversion, by going through UTF-16.
|
||||
*/
|
||||
// TODO!
|
||||
#error "Need to implement double conversion!"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find any newline character in the buffer,
|
||||
* write the part BEFORE the newline, then write
|
||||
* a carriage-return + newline, and then write
|
||||
* the remaining part of the buffer.
|
||||
*
|
||||
* This fixes output in files and serial console.
|
||||
*/
|
||||
while (len > 0)
|
||||
{
|
||||
/* Loop until we find a \r or \n character */
|
||||
// FIXME: What about the pair \r\n ?
|
||||
p = szStr;
|
||||
while (len > 0 && *(PCHAR)p != '\r' && *(PCHAR)p != '\n')
|
||||
{
|
||||
/* Advance one character */
|
||||
p = (PVOID)((PCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Write everything up to \r or \n */
|
||||
dwNumBytes = ((PCHAR)p - (PCHAR)szStr) * sizeof(CHAR);
|
||||
WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
|
||||
|
||||
/* If we hit \r or \n ... */
|
||||
if (len > 0 && (*(PCHAR)p == '\r' || *(PCHAR)p == '\n'))
|
||||
{
|
||||
/* ... send a carriage-return + newline sequence and skip \r or \n */
|
||||
WriteFile(Stream->hHandle, "\r\n", 2, &dwNumBytes, NULL);
|
||||
szStr = (PVOID)((PCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _UNICODE
|
||||
HeapFree(GetProcessHeap(), 0, buffer);
|
||||
#else
|
||||
// TODO!
|
||||
#endif
|
||||
}
|
||||
else // if (Stream->Mode == Binary)
|
||||
{
|
||||
/* Directly output the string */
|
||||
WriteFile(Stream->hHandle, szStr, len, &dwNumBytes, NULL);
|
||||
}
|
||||
|
||||
// FIXME!
|
||||
return (INT)TotalLen;
|
||||
|
||||
#else /* defined(USE_CRT) */
|
||||
|
||||
DWORD total = len;
|
||||
DWORD written = 0;
|
||||
|
||||
/* If we do not write anything, just return */
|
||||
if (!szStr || len == 0)
|
||||
return 0;
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* There is no "counted" printf-to-stream or puts-like function, therefore
|
||||
* we use this trick to output the counted string to the stream.
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
written = fwprintf(Stream->fStream, L"%.*s", total, szStr);
|
||||
if (written < total)
|
||||
{
|
||||
/*
|
||||
* Some embedded NULL or special character
|
||||
* was encountered, print it apart.
|
||||
*/
|
||||
if (written == 0)
|
||||
{
|
||||
fputwc(*szStr, Stream->fStream);
|
||||
written++;
|
||||
}
|
||||
|
||||
szStr += written;
|
||||
total -= written;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (INT)len;
|
||||
#else
|
||||
/* ANSI text or Binary output only */
|
||||
_setmode(_fileno(Stream->fStream), _O_TEXT); // _O_BINARY
|
||||
return fwrite(szStr, sizeof(*szStr), len, Stream->fStream);
|
||||
#endif
|
||||
|
||||
#endif /* defined(USE_CRT) */
|
||||
}
|
||||
|
||||
|
||||
#define CON_STREAM_WRITE_CALL(Stream, Str, Len) \
|
||||
(Stream)->WriteFunc((Stream), (Str), (Len));
|
||||
|
||||
/* Lock the stream only in non-USE_CRT mode (otherwise use the CRT stream lock) */
|
||||
#ifndef USE_CRT
|
||||
|
||||
#define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
|
||||
do { \
|
||||
EnterCriticalSection(&(Stream)->Lock); \
|
||||
(RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
LeaveCriticalSection(&(Stream)->Lock); \
|
||||
} while(0)
|
||||
|
||||
#define CON_STREAM_WRITE(Stream, Str, Len) \
|
||||
do { \
|
||||
EnterCriticalSection(&(Stream)->Lock); \
|
||||
CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
LeaveCriticalSection(&(Stream)->Lock); \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
|
||||
do { \
|
||||
(RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
} while(0)
|
||||
|
||||
#define CON_STREAM_WRITE(Stream, Str, Len) \
|
||||
do { \
|
||||
CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
INT
|
||||
ConStreamWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len)
|
||||
{
|
||||
INT Len;
|
||||
CON_STREAM_WRITE2(Stream, szStr, len, Len);
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr)
|
||||
{
|
||||
INT Len;
|
||||
|
||||
Len = wcslen(szStr);
|
||||
CON_STREAM_WRITE2(Stream, szStr, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
|
||||
|
||||
// Len = vfwprintf(Stream->fStream, szStr, args); // vfprintf for direct ANSI
|
||||
|
||||
/*
|
||||
* Reuse szStr as the pointer to end-of-string, to compute
|
||||
* the string length instead of calling wcslen().
|
||||
*/
|
||||
// StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
|
||||
// Len = wcslen(bufSrc);
|
||||
StringCchVPrintfExW(bufSrc, ARRAYSIZE(bufSrc), &szStr, NULL, 0, szStr, args);
|
||||
Len = szStr - bufSrc;
|
||||
|
||||
CON_STREAM_WRITE2(Stream, bufSrc, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
// Len = vfwprintf(Stream->fStream, szMsgBuf, args); // vfprintf for direct ANSI
|
||||
|
||||
// StringCchPrintfW
|
||||
va_start(args, szStr);
|
||||
Len = ConPrintfV(Stream, szStr, args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPutsEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID)
|
||||
{
|
||||
INT Len;
|
||||
PWCHAR szStr = NULL;
|
||||
|
||||
Len = K32LoadStringW(hInstance, uID, (PWSTR)&szStr, 0);
|
||||
if (szStr && Len)
|
||||
// Len = ConPuts(Stream, szStr);
|
||||
CON_STREAM_WRITE2(Stream, szStr, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID)
|
||||
{
|
||||
return ConResPutsEx(Stream, NULL /*GetModuleHandleW(NULL)*/, uID);
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPrintfExV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
|
||||
|
||||
// NOTE: We may use the special behaviour where nBufMaxSize == 0
|
||||
Len = K32LoadStringW(hInstance, uID, bufSrc, ARRAYSIZE(bufSrc));
|
||||
if (Len)
|
||||
Len = ConPrintfV(Stream, bufSrc, args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
return ConResPrintfExV(Stream, NULL /*GetModuleHandleW(NULL)*/, uID, args);
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintfEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
va_start(args, uID);
|
||||
Len = ConResPrintfExV(Stream, hInstance, uID, args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
va_start(args, uID);
|
||||
Len = ConResPrintfV(Stream, uID, args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConMsgPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId)
|
||||
{
|
||||
INT Len;
|
||||
DWORD dwLength = 0;
|
||||
LPWSTR lpMsgBuf = NULL;
|
||||
|
||||
/*
|
||||
* Sanitize dwFlags. This version always ignore explicitely the inserts
|
||||
* as we emulate the behaviour of the *puts function.
|
||||
*/
|
||||
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
|
||||
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
|
||||
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
|
||||
|
||||
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
/*
|
||||
* Retrieve the message string without appending extra newlines.
|
||||
* Wrap in SEH to protect from invalid string parameters.
|
||||
*/
|
||||
_SEH2_TRY
|
||||
{
|
||||
dwLength = FormatMessageW(dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
(LPWSTR)&lpMsgBuf,
|
||||
0, NULL);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
Len = (INT)dwLength;
|
||||
|
||||
if (!lpMsgBuf)
|
||||
{
|
||||
// ASSERT(dwLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASSERT(dwLength != 0);
|
||||
|
||||
/* lpMsgBuf is NULL-terminated by FormatMessage */
|
||||
// Len = ConPuts(Stream, lpMsgBuf);
|
||||
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
/* Free the buffer allocated by FormatMessage */
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConMsgPrintf2V(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
DWORD dwLength = 0;
|
||||
LPWSTR lpMsgBuf = NULL;
|
||||
|
||||
/*
|
||||
* Sanitize dwFlags. This version always ignore explicitely the inserts.
|
||||
* The string that we will return to the user will not be pre-formatted.
|
||||
*/
|
||||
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
|
||||
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
|
||||
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
|
||||
|
||||
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
/*
|
||||
* Retrieve the message string without appending extra newlines.
|
||||
* Wrap in SEH to protect from invalid string parameters.
|
||||
*/
|
||||
_SEH2_TRY
|
||||
{
|
||||
dwLength = FormatMessageW(dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
(LPWSTR)&lpMsgBuf,
|
||||
0, NULL);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
Len = (INT)dwLength;
|
||||
|
||||
if (!lpMsgBuf)
|
||||
{
|
||||
// ASSERT(dwLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASSERT(dwLength != 0);
|
||||
|
||||
/* lpMsgBuf is NULL-terminated by FormatMessage */
|
||||
Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||
// CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
/* Free the buffer allocated by FormatMessage */
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConMsgPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
DWORD dwLength = 0;
|
||||
LPWSTR lpMsgBuf = NULL;
|
||||
|
||||
/* Sanitize dwFlags */
|
||||
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
|
||||
// dwFlags &= ~FORMAT_MESSAGE_IGNORE_INSERTS; // We always use arguments.
|
||||
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY; // We always use arguments of type 'va_list'.
|
||||
|
||||
//
|
||||
// NOTE: Technique taken from eventvwr.c!GetMessageStringFromDll()
|
||||
//
|
||||
|
||||
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
/*
|
||||
* Retrieve the message string without appending extra newlines.
|
||||
* Use the "safe" FormatMessage version (SEH-protected) to protect
|
||||
* from invalid string parameters.
|
||||
*/
|
||||
dwLength = FormatMessageSafeW(dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
(LPWSTR)&lpMsgBuf,
|
||||
0, &args);
|
||||
|
||||
Len = (INT)dwLength;
|
||||
|
||||
if (!lpMsgBuf)
|
||||
{
|
||||
// ASSERT(dwLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASSERT(dwLength != 0);
|
||||
|
||||
// Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
/* Free the buffer allocated by FormatMessage */
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConMsgPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
va_start(args, dwLanguageId);
|
||||
// ConMsgPrintf2V
|
||||
Len = ConMsgPrintfV(Stream,
|
||||
dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream)
|
||||
{
|
||||
HANDLE hOutput = ConStreamGetOSHandle(Stream);
|
||||
|
||||
/*
|
||||
* Erase the full line where the cursor is, and move
|
||||
* the cursor back to the beginning of the line.
|
||||
*/
|
||||
|
||||
if (IsConsoleHandle(hOutput))
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
DWORD dwWritten;
|
||||
|
||||
GetConsoleScreenBufferInfo(hOutput, &csbi);
|
||||
|
||||
csbi.dwCursorPosition.X = 0;
|
||||
// csbi.dwCursorPosition.Y;
|
||||
|
||||
FillConsoleOutputCharacterW(hOutput, L' ',
|
||||
csbi.dwSize.X,
|
||||
csbi.dwCursorPosition,
|
||||
&dwWritten);
|
||||
SetConsoleCursorPosition(hOutput, csbi.dwCursorPosition);
|
||||
}
|
||||
else if (IsTTYHandle(hOutput))
|
||||
{
|
||||
ConPuts(Stream, L"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
|
||||
}
|
||||
// else, do nothing for files
|
||||
}
|
||||
|
||||
/* EOF */
|
162
sdk/lib/conutils/outstream.h
Normal file
162
sdk/lib/conutils/outstream.h
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __OUTSTREAM_H__
|
||||
#define __OUTSTREAM_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Enable this define if you want to only use CRT functions to output
|
||||
* UNICODE stream to the console, as in the way explained by
|
||||
* http://archives.miloush.net/michkap/archive/2008/03/18/8306597.html
|
||||
*/
|
||||
/** NOTE: Experimental! Don't use USE_CRT yet because output to console is a bit broken **/
|
||||
// #define USE_CRT
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Shadow type, implementation-specific
|
||||
typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM;
|
||||
|
||||
// typedef INT (__stdcall *CON_READ_FUNC)(IN PCON_STREAM, IN PTCHAR, IN DWORD);
|
||||
// Stream, szStr, len
|
||||
typedef INT (__stdcall *CON_WRITE_FUNC)(IN PCON_STREAM, IN PTCHAR, IN DWORD);
|
||||
|
||||
|
||||
/*
|
||||
* Console I/O utility API -- Output
|
||||
*/
|
||||
|
||||
INT
|
||||
__stdcall
|
||||
ConWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len);
|
||||
|
||||
INT
|
||||
ConStreamWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len);
|
||||
|
||||
INT
|
||||
ConPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr);
|
||||
|
||||
INT
|
||||
ConPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConResPutsEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID);
|
||||
|
||||
INT
|
||||
ConResPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID);
|
||||
|
||||
INT
|
||||
ConResPrintfExV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
ConResPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintfEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
...);
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConMsgPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId);
|
||||
|
||||
INT
|
||||
ConMsgPrintf2V(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
ConMsgPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConMsgPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
...);
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __OUTSTREAM_H__ */
|
||||
|
||||
/* EOF */
|
@ -1,19 +1,15 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/pager.c
|
||||
* PURPOSE: Console/terminal paging functionality.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Console/terminal paging functionality.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
// #include <winnls.h>
|
||||
@ -158,3 +154,5 @@ ConResPaging(
|
||||
return ConResPagingEx(Pager, PagePrompt, StartPaging,
|
||||
NULL /*GetModuleHandleW(NULL)*/, uID);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
@ -1,16 +1,16 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/pager.h
|
||||
* PURPOSE: Console/terminal paging functionality.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Console/terminal paging functionality.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __PAGER_H__
|
||||
#define __PAGER_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
@ -42,6 +42,7 @@ do { \
|
||||
(pPager)->LineCount = 0; \
|
||||
} while (0)
|
||||
|
||||
|
||||
// Pager, Done, Total
|
||||
typedef BOOL (__stdcall *PAGE_PROMPT)(IN PCON_PAGER, IN DWORD, IN DWORD);
|
||||
|
||||
@ -78,4 +79,7 @@ ConResPaging(
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __PAGER_H__ */
|
||||
|
||||
/* EOF */
|
||||
|
@ -1,19 +1,15 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/screen.c
|
||||
* PURPOSE: Console/terminal screen management.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Console/terminal screen management.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
#define UNICODE
|
||||
#define _UNICODE
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
// #include <winnls.h>
|
||||
@ -173,3 +169,5 @@ ConClearScreen(IN PCON_SCREEN Screen)
|
||||
CON_STREAM_WRITE(Screen->Stream, &ch, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
@ -1,16 +1,16 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/screen.h
|
||||
* PURPOSE: Console/terminal screen management.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Console/terminal screen management.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __SCREEN_H__
|
||||
#define __SCREEN_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
@ -60,4 +60,7 @@ ConClearScreen(IN PCON_SCREEN Screen);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SCREEN_H__ */
|
||||
|
||||
/* EOF */
|
||||
|
@ -1,13 +1,11 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/stream.c
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -27,63 +25,22 @@
|
||||
#include <io.h>
|
||||
#endif /* USE_CRT */
|
||||
|
||||
#include <stdlib.h> // limits.h // For MB_LEN_MAX
|
||||
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
#include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
|
||||
// #include <winuser.h> // MAKEINTRESOURCEW, RT_STRING
|
||||
#include <wincon.h> // Console APIs (only if kernel32 support included)
|
||||
#include <strsafe.h>
|
||||
|
||||
/* PSEH for SEH Support */
|
||||
#include <pseh/pseh2.h>
|
||||
|
||||
#include "conutils.h"
|
||||
#include "stream.h"
|
||||
|
||||
|
||||
// #define RC_STRING_MAX_SIZE 4096
|
||||
#define CON_RC_STRING_MAX_SIZE 4096
|
||||
// #define MAX_BUFFER_SIZE 4096 // Some programs (wlanconf, shutdown) set it to 5024
|
||||
// #define OUTPUT_BUFFER_SIZE 4096 // Name given in cmd/console.c
|
||||
// MAX_STRING_SIZE // Name given in diskpart
|
||||
|
||||
// #define MAX_MESSAGE_SIZE 512 // See shutdown...
|
||||
#include "stream_private.h"
|
||||
|
||||
|
||||
/*
|
||||
* Console I/O streams
|
||||
*/
|
||||
|
||||
typedef struct _CON_STREAM
|
||||
{
|
||||
CON_WRITE_FUNC WriteFunc;
|
||||
|
||||
#ifdef USE_CRT
|
||||
FILE* fStream;
|
||||
#else
|
||||
BOOL IsInitialized;
|
||||
CRITICAL_SECTION Lock;
|
||||
|
||||
HANDLE hHandle;
|
||||
|
||||
/*
|
||||
* TRUE if 'hHandle' refers to a console, in which case I/O UTF-16
|
||||
* is directly used. If 'hHandle' refers to a file or a pipe, the
|
||||
* 'Mode' flag is used.
|
||||
*/
|
||||
BOOL IsConsole;
|
||||
|
||||
/*
|
||||
* The 'Mode' flag is used to know the translation mode
|
||||
* when 'hHandle' refers to a file or a pipe.
|
||||
*/
|
||||
CON_STREAM_MODE Mode;
|
||||
UINT CodePage; // Used to convert UTF-16 text to some ANSI codepage.
|
||||
#endif /* defined(USE_CRT) */
|
||||
} CON_STREAM, *PCON_STREAM;
|
||||
|
||||
/*
|
||||
* Standard console streams, initialized by
|
||||
* calls to ConStreamInit/ConInitStdStreams.
|
||||
@ -339,713 +296,4 @@ ConStreamSetOSHandle(
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Console I/O utility API
|
||||
* (for the moment, only Output)
|
||||
*/
|
||||
|
||||
// NOTE: Should be called with the stream locked.
|
||||
INT
|
||||
__stdcall
|
||||
ConWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len)
|
||||
{
|
||||
#ifndef USE_CRT
|
||||
DWORD TotalLen = len, dwNumBytes = 0;
|
||||
PVOID p;
|
||||
|
||||
// CHAR strOem[CON_RC_STRING_MAX_SIZE]; // Some static buffer...
|
||||
|
||||
/* If we do not write anything, just return */
|
||||
if (!szStr || len == 0)
|
||||
return 0;
|
||||
|
||||
/* Check whether we are writing to a console */
|
||||
// if (IsConsoleHandle(Stream->hHandle))
|
||||
if (Stream->IsConsole)
|
||||
{
|
||||
// TODO: Check if (ConStream->Mode == WideText or UTF16Text) ??
|
||||
|
||||
/*
|
||||
* This code is inspired from _cputws, in particular from the fact that,
|
||||
* according to MSDN: https://msdn.microsoft.com/en-us/library/ms687401(v=vs.85).aspx
|
||||
* the buffer size must be less than 64 KB.
|
||||
*
|
||||
* A similar code can be used for implementing _cputs too.
|
||||
*/
|
||||
|
||||
DWORD cchWrite;
|
||||
TotalLen = len, dwNumBytes = 0;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
cchWrite = min(len, 65535 / sizeof(WCHAR));
|
||||
|
||||
// FIXME: Check return value!
|
||||
WriteConsole(Stream->hHandle, szStr, cchWrite, &dwNumBytes, NULL);
|
||||
|
||||
szStr += cchWrite;
|
||||
len -= cchWrite;
|
||||
}
|
||||
|
||||
return (INT)TotalLen; // FIXME: Really return the number of chars written!
|
||||
}
|
||||
|
||||
/*
|
||||
* We are redirected and writing to a file or pipe instead of the console.
|
||||
* Convert the string from TCHARs to the desired output format, if the two differ.
|
||||
*
|
||||
* Implementation NOTE:
|
||||
* MultiByteToWideChar (resp. WideCharToMultiByte) are equivalent to
|
||||
* OemToCharBuffW (resp. CharToOemBuffW), but the latters uselessly
|
||||
* depend on user32.dll, while MultiByteToWideChar and WideCharToMultiByte
|
||||
* only need kernel32.dll.
|
||||
*/
|
||||
if ((Stream->Mode == WideText) || (Stream->Mode == UTF16Text))
|
||||
{
|
||||
#ifndef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
|
||||
/* Convert from the current process/thread's codepage to UTF-16 */
|
||||
WCHAR *buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
|
||||
if (!buffer)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
len = (DWORD)MultiByteToWideChar(CP_THREAD_ACP, // CP_ACP, CP_OEMCP
|
||||
0, szStr, (INT)len, buffer, (INT)len);
|
||||
szStr = (PVOID)buffer;
|
||||
#else
|
||||
/*
|
||||
* Do not perform any conversion since we are already in UTF-16,
|
||||
* that is the same encoding as the stream.
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find any newline character in the buffer,
|
||||
* write the part BEFORE the newline, then write
|
||||
* a carriage-return + newline, and then write
|
||||
* the remaining part of the buffer.
|
||||
*
|
||||
* This fixes output in files and serial console.
|
||||
*/
|
||||
while (len > 0)
|
||||
{
|
||||
/* Loop until we find a \r or \n character */
|
||||
// FIXME: What about the pair \r\n ?
|
||||
p = szStr;
|
||||
while (len > 0 && *(PWCHAR)p != L'\r' && *(PWCHAR)p != L'\n')
|
||||
{
|
||||
/* Advance one character */
|
||||
p = (PVOID)((PWCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Write everything up to \r or \n */
|
||||
dwNumBytes = ((PWCHAR)p - (PWCHAR)szStr) * sizeof(WCHAR);
|
||||
WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
|
||||
|
||||
/* If we hit \r or \n ... */
|
||||
if (len > 0 && (*(PWCHAR)p == L'\r' || *(PWCHAR)p == L'\n'))
|
||||
{
|
||||
/* ... send a carriage-return + newline sequence and skip \r or \n */
|
||||
WriteFile(Stream->hHandle, L"\r\n", 2 * sizeof(WCHAR), &dwNumBytes, NULL);
|
||||
szStr = (PVOID)((PWCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _UNICODE
|
||||
HeapFree(GetProcessHeap(), 0, buffer);
|
||||
#endif
|
||||
}
|
||||
else if ((Stream->Mode == UTF8Text) || (Stream->Mode == AnsiText))
|
||||
{
|
||||
CHAR *buffer;
|
||||
|
||||
/*
|
||||
* Resolve the codepage cache if it was not assigned yet
|
||||
* (only if the stream is in ANSI mode; in UTF8 mode the
|
||||
* codepage was already set to CP_UTF8).
|
||||
*/
|
||||
if (/*(Stream->Mode == AnsiText) &&*/ (Stream->CodePage == INVALID_CP))
|
||||
Stream->CodePage = GetConsoleOutputCP(); // CP_ACP, CP_OEMCP
|
||||
|
||||
#ifdef _UNICODE // UNICODE means that TCHAR == WCHAR == UTF-16
|
||||
/* Convert from UTF-16 to either UTF-8 or ANSI, using stream codepage */
|
||||
// NOTE: MB_LEN_MAX defined either in limits.h or in stdlib.h .
|
||||
buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * MB_LEN_MAX);
|
||||
if (!buffer)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
len = WideCharToMultiByte(Stream->CodePage, 0,
|
||||
szStr, len, buffer, len * MB_LEN_MAX,
|
||||
NULL, NULL);
|
||||
szStr = (PVOID)buffer;
|
||||
#else
|
||||
/*
|
||||
* Convert from the current process/thread's codepage to either
|
||||
* UTF-8 or ANSI, using stream codepage.
|
||||
* We need to perform a double conversion, by going through UTF-16.
|
||||
*/
|
||||
// TODO!
|
||||
#error "Need to implement double conversion!"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find any newline character in the buffer,
|
||||
* write the part BEFORE the newline, then write
|
||||
* a carriage-return + newline, and then write
|
||||
* the remaining part of the buffer.
|
||||
*
|
||||
* This fixes output in files and serial console.
|
||||
*/
|
||||
while (len > 0)
|
||||
{
|
||||
/* Loop until we find a \r or \n character */
|
||||
// FIXME: What about the pair \r\n ?
|
||||
p = szStr;
|
||||
while (len > 0 && *(PCHAR)p != '\r' && *(PCHAR)p != '\n')
|
||||
{
|
||||
/* Advance one character */
|
||||
p = (PVOID)((PCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
|
||||
/* Write everything up to \r or \n */
|
||||
dwNumBytes = ((PCHAR)p - (PCHAR)szStr) * sizeof(CHAR);
|
||||
WriteFile(Stream->hHandle, szStr, dwNumBytes, &dwNumBytes, NULL);
|
||||
|
||||
/* If we hit \r or \n ... */
|
||||
if (len > 0 && (*(PCHAR)p == '\r' || *(PCHAR)p == '\n'))
|
||||
{
|
||||
/* ... send a carriage-return + newline sequence and skip \r or \n */
|
||||
WriteFile(Stream->hHandle, "\r\n", 2, &dwNumBytes, NULL);
|
||||
szStr = (PVOID)((PCHAR)p + 1);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _UNICODE
|
||||
HeapFree(GetProcessHeap(), 0, buffer);
|
||||
#else
|
||||
// TODO!
|
||||
#endif
|
||||
}
|
||||
else // if (Stream->Mode == Binary)
|
||||
{
|
||||
/* Directly output the string */
|
||||
WriteFile(Stream->hHandle, szStr, len, &dwNumBytes, NULL);
|
||||
}
|
||||
|
||||
// FIXME!
|
||||
return (INT)TotalLen;
|
||||
|
||||
#else /* defined(USE_CRT) */
|
||||
|
||||
DWORD total = len;
|
||||
DWORD written = 0;
|
||||
|
||||
/* If we do not write anything, just return */
|
||||
if (!szStr || len == 0)
|
||||
return 0;
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* There is no "counted" printf-to-stream or puts-like function, therefore
|
||||
* we use this trick to output the counted string to the stream.
|
||||
*/
|
||||
while (1)
|
||||
{
|
||||
written = fwprintf(Stream->fStream, L"%.*s", total, szStr);
|
||||
if (written < total)
|
||||
{
|
||||
/*
|
||||
* Some embedded NULL or special character
|
||||
* was encountered, print it apart.
|
||||
*/
|
||||
if (written == 0)
|
||||
{
|
||||
fputwc(*szStr, Stream->fStream);
|
||||
written++;
|
||||
}
|
||||
|
||||
szStr += written;
|
||||
total -= written;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (INT)len;
|
||||
#else
|
||||
/* ANSI text or Binary output only */
|
||||
_setmode(_fileno(Stream->fStream), _O_TEXT); // _O_BINARY
|
||||
return fwrite(szStr, sizeof(*szStr), len, Stream->fStream);
|
||||
#endif
|
||||
|
||||
#endif /* defined(USE_CRT) */
|
||||
}
|
||||
|
||||
|
||||
#define CON_STREAM_WRITE_CALL(Stream, Str, Len) \
|
||||
(Stream)->WriteFunc((Stream), (Str), (Len));
|
||||
|
||||
/* Lock the stream only in non-USE_CRT mode (otherwise use the CRT stream lock) */
|
||||
#ifndef USE_CRT
|
||||
|
||||
#define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
|
||||
do { \
|
||||
EnterCriticalSection(&(Stream)->Lock); \
|
||||
(RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
LeaveCriticalSection(&(Stream)->Lock); \
|
||||
} while(0)
|
||||
|
||||
#define CON_STREAM_WRITE(Stream, Str, Len) \
|
||||
do { \
|
||||
EnterCriticalSection(&(Stream)->Lock); \
|
||||
CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
LeaveCriticalSection(&(Stream)->Lock); \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#define CON_STREAM_WRITE2(Stream, Str, Len, RetLen) \
|
||||
do { \
|
||||
(RetLen) = CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
} while(0)
|
||||
|
||||
#define CON_STREAM_WRITE(Stream, Str, Len) \
|
||||
do { \
|
||||
CON_STREAM_WRITE_CALL((Stream), (Str), (Len)); \
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
INT
|
||||
ConStreamWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len)
|
||||
{
|
||||
INT Len;
|
||||
CON_STREAM_WRITE2(Stream, szStr, len, Len);
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr)
|
||||
{
|
||||
INT Len;
|
||||
|
||||
Len = wcslen(szStr);
|
||||
CON_STREAM_WRITE2(Stream, szStr, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
|
||||
|
||||
// Len = vfwprintf(Stream->fStream, szStr, args); // vfprintf for direct ANSI
|
||||
|
||||
/*
|
||||
* Reuse szStr as the pointer to end-of-string, to compute
|
||||
* the string length instead of calling wcslen().
|
||||
*/
|
||||
// StringCchVPrintfW(bufSrc, ARRAYSIZE(bufSrc), szStr, args);
|
||||
// Len = wcslen(bufSrc);
|
||||
StringCchVPrintfExW(bufSrc, ARRAYSIZE(bufSrc), &szStr, NULL, 0, szStr, args);
|
||||
Len = szStr - bufSrc;
|
||||
|
||||
CON_STREAM_WRITE2(Stream, bufSrc, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
// Len = vfwprintf(Stream->fStream, szMsgBuf, args); // vfprintf for direct ANSI
|
||||
|
||||
// StringCchPrintfW
|
||||
va_start(args, szStr);
|
||||
Len = ConPrintfV(Stream, szStr, args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPutsEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID)
|
||||
{
|
||||
INT Len;
|
||||
PWCHAR szStr = NULL;
|
||||
|
||||
Len = K32LoadStringW(hInstance, uID, (PWSTR)&szStr, 0);
|
||||
if (szStr && Len)
|
||||
// Len = ConPuts(Stream, szStr);
|
||||
CON_STREAM_WRITE2(Stream, szStr, Len, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID)
|
||||
{
|
||||
return ConResPutsEx(Stream, NULL /*GetModuleHandleW(NULL)*/, uID);
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPrintfExV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
WCHAR bufSrc[CON_RC_STRING_MAX_SIZE];
|
||||
|
||||
// NOTE: We may use the special behaviour where nBufMaxSize == 0
|
||||
Len = K32LoadStringW(hInstance, uID, bufSrc, ARRAYSIZE(bufSrc));
|
||||
if (Len)
|
||||
Len = ConPrintfV(Stream, bufSrc, args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConResPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
return ConResPrintfExV(Stream, NULL /*GetModuleHandleW(NULL)*/, uID, args);
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintfEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
va_start(args, uID);
|
||||
Len = ConResPrintfExV(Stream, hInstance, uID, args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
va_start(args, uID);
|
||||
Len = ConResPrintfV(Stream, uID, args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConMsgPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId)
|
||||
{
|
||||
INT Len;
|
||||
DWORD dwLength = 0;
|
||||
LPWSTR lpMsgBuf = NULL;
|
||||
|
||||
/*
|
||||
* Sanitize dwFlags. This version always ignore explicitely the inserts
|
||||
* as we emulate the behaviour of the *puts function.
|
||||
*/
|
||||
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
|
||||
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
|
||||
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
|
||||
|
||||
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
/*
|
||||
* Retrieve the message string without appending extra newlines.
|
||||
* Wrap in SEH to protect from invalid string parameters.
|
||||
*/
|
||||
_SEH2_TRY
|
||||
{
|
||||
dwLength = FormatMessageW(dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
(LPWSTR)&lpMsgBuf,
|
||||
0, NULL);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
Len = (INT)dwLength;
|
||||
|
||||
if (!lpMsgBuf)
|
||||
{
|
||||
// ASSERT(dwLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASSERT(dwLength != 0);
|
||||
|
||||
/* lpMsgBuf is NULL-terminated by FormatMessage */
|
||||
// Len = ConPuts(Stream, lpMsgBuf);
|
||||
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
/* Free the buffer allocated by FormatMessage */
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConMsgPrintf2V(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
DWORD dwLength = 0;
|
||||
LPWSTR lpMsgBuf = NULL;
|
||||
|
||||
/*
|
||||
* Sanitize dwFlags. This version always ignore explicitely the inserts.
|
||||
* The string that we will return to the user will not be pre-formatted.
|
||||
*/
|
||||
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
|
||||
dwFlags |= FORMAT_MESSAGE_IGNORE_INSERTS; // Ignore inserts for FormatMessage.
|
||||
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY;
|
||||
|
||||
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
/*
|
||||
* Retrieve the message string without appending extra newlines.
|
||||
* Wrap in SEH to protect from invalid string parameters.
|
||||
*/
|
||||
_SEH2_TRY
|
||||
{
|
||||
dwLength = FormatMessageW(dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
(LPWSTR)&lpMsgBuf,
|
||||
0, NULL);
|
||||
}
|
||||
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
}
|
||||
_SEH2_END;
|
||||
|
||||
Len = (INT)dwLength;
|
||||
|
||||
if (!lpMsgBuf)
|
||||
{
|
||||
// ASSERT(dwLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASSERT(dwLength != 0);
|
||||
|
||||
/* lpMsgBuf is NULL-terminated by FormatMessage */
|
||||
Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||
// CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
/* Free the buffer allocated by FormatMessage */
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
ConMsgPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args) // arg_ptr
|
||||
{
|
||||
INT Len;
|
||||
DWORD dwLength = 0;
|
||||
LPWSTR lpMsgBuf = NULL;
|
||||
|
||||
/* Sanitize dwFlags */
|
||||
dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; // Always allocate an internal buffer.
|
||||
// dwFlags &= ~FORMAT_MESSAGE_IGNORE_INSERTS; // We always use arguments.
|
||||
dwFlags &= ~FORMAT_MESSAGE_ARGUMENT_ARRAY; // We always use arguments of type 'va_list'.
|
||||
|
||||
//
|
||||
// NOTE: Technique taken from eventvwr.c!GetMessageStringFromDll()
|
||||
//
|
||||
|
||||
dwFlags |= FORMAT_MESSAGE_MAX_WIDTH_MASK;
|
||||
|
||||
/*
|
||||
* Retrieve the message string without appending extra newlines.
|
||||
* Use the "safe" FormatMessage version (SEH-protected) to protect
|
||||
* from invalid string parameters.
|
||||
*/
|
||||
dwLength = FormatMessageSafeW(dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
(LPWSTR)&lpMsgBuf,
|
||||
0, &args);
|
||||
|
||||
Len = (INT)dwLength;
|
||||
|
||||
if (!lpMsgBuf)
|
||||
{
|
||||
// ASSERT(dwLength == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ASSERT(dwLength != 0);
|
||||
|
||||
// Len = ConPrintfV(Stream, lpMsgBuf, args);
|
||||
CON_STREAM_WRITE2(Stream, lpMsgBuf, dwLength, Len);
|
||||
|
||||
/* Fixup returned length in case of errors */
|
||||
if (Len < 0)
|
||||
Len = 0;
|
||||
|
||||
/* Free the buffer allocated by FormatMessage */
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConMsgPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
...)
|
||||
{
|
||||
INT Len;
|
||||
va_list args;
|
||||
|
||||
va_start(args, dwLanguageId);
|
||||
// ConMsgPrintf2V
|
||||
Len = ConMsgPrintfV(Stream,
|
||||
dwFlags,
|
||||
lpSource,
|
||||
dwMessageId,
|
||||
dwLanguageId,
|
||||
args);
|
||||
va_end(args);
|
||||
|
||||
return Len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream)
|
||||
{
|
||||
HANDLE hOutput = ConStreamGetOSHandle(Stream);
|
||||
|
||||
/*
|
||||
* Erase the full line where the cursor is, and move
|
||||
* the cursor back to the beginning of the line.
|
||||
*/
|
||||
|
||||
if (IsConsoleHandle(hOutput))
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
DWORD dwWritten;
|
||||
|
||||
GetConsoleScreenBufferInfo(hOutput, &csbi);
|
||||
|
||||
csbi.dwCursorPosition.X = 0;
|
||||
// csbi.dwCursorPosition.Y;
|
||||
|
||||
FillConsoleOutputCharacterW(hOutput, L' ',
|
||||
csbi.dwSize.X,
|
||||
csbi.dwCursorPosition,
|
||||
&dwWritten);
|
||||
SetConsoleCursorPosition(hOutput, csbi.dwCursorPosition);
|
||||
}
|
||||
else if (IsTTYHandle(hOutput))
|
||||
{
|
||||
ConPuts(Stream, L"\x1B[2K\x1B[1G"); // FIXME: Just use WriteFile
|
||||
}
|
||||
// else, do nothing for files
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
@ -1,18 +1,18 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/stream.h
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __STREAM_H__
|
||||
#define __STREAM_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Enable this define if you want to only use CRT functions to output
|
||||
* UNICODE stream to the console, as in the way explained by
|
||||
@ -152,124 +152,10 @@ ConStreamSetOSHandle(
|
||||
IN HANDLE Handle);
|
||||
|
||||
|
||||
/*
|
||||
* Console I/O utility API
|
||||
* (for the moment, only Output)
|
||||
*/
|
||||
|
||||
INT
|
||||
__stdcall
|
||||
ConWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len);
|
||||
|
||||
INT
|
||||
ConStreamWrite(
|
||||
IN PCON_STREAM Stream,
|
||||
IN PTCHAR szStr,
|
||||
IN DWORD len);
|
||||
|
||||
INT
|
||||
ConPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr);
|
||||
|
||||
INT
|
||||
ConPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN LPWSTR szStr,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConResPutsEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID);
|
||||
|
||||
INT
|
||||
ConResPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID);
|
||||
|
||||
INT
|
||||
ConResPrintfExV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
ConResPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintfEx(
|
||||
IN PCON_STREAM Stream,
|
||||
IN HINSTANCE hInstance OPTIONAL,
|
||||
IN UINT uID,
|
||||
...);
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConResPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN UINT uID,
|
||||
...);
|
||||
|
||||
INT
|
||||
ConMsgPuts(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId);
|
||||
|
||||
INT
|
||||
ConMsgPrintf2V(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
ConMsgPrintfV(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
IN va_list args); // arg_ptr
|
||||
|
||||
INT
|
||||
__cdecl
|
||||
ConMsgPrintf(
|
||||
IN PCON_STREAM Stream,
|
||||
IN DWORD dwFlags,
|
||||
IN LPCVOID lpSource OPTIONAL,
|
||||
IN DWORD dwMessageId,
|
||||
IN DWORD dwLanguageId,
|
||||
...);
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
ConClearLine(IN PCON_STREAM Stream);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __STREAM_H__ */
|
||||
|
||||
/* EOF */
|
||||
|
55
sdk/lib/conutils/stream_private.h
Normal file
55
sdk/lib/conutils/stream_private.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Provides basic abstraction wrappers around CRT streams or
|
||||
* Win32 console API I/O functions, to deal with i18n + Unicode
|
||||
* related problems.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __STREAM_PRIVATE_H__
|
||||
#define __STREAM_PRIVATE_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Console I/O streams
|
||||
*/
|
||||
|
||||
#if 0
|
||||
// Shadow type, implementation-specific
|
||||
typedef struct _CON_STREAM CON_STREAM, *PCON_STREAM;
|
||||
#endif
|
||||
|
||||
typedef struct _CON_STREAM
|
||||
{
|
||||
CON_WRITE_FUNC WriteFunc;
|
||||
|
||||
#ifdef USE_CRT
|
||||
FILE* fStream;
|
||||
#else
|
||||
BOOL IsInitialized;
|
||||
CRITICAL_SECTION Lock;
|
||||
|
||||
HANDLE hHandle;
|
||||
|
||||
/*
|
||||
* TRUE if 'hHandle' refers to a console, in which case I/O UTF-16
|
||||
* is directly used. If 'hHandle' refers to a file or a pipe, the
|
||||
* 'Mode' flag is used.
|
||||
*/
|
||||
BOOL IsConsole;
|
||||
|
||||
/*
|
||||
* The 'Mode' flag is used to know the translation mode
|
||||
* when 'hHandle' refers to a file or a pipe.
|
||||
*/
|
||||
CON_STREAM_MODE Mode;
|
||||
UINT CodePage; // Used to convert UTF-16 text to some ANSI codepage.
|
||||
#endif /* defined(USE_CRT) */
|
||||
} CON_STREAM, *PCON_STREAM;
|
||||
|
||||
#endif /* __STREAM_PRIVATE_H__ */
|
||||
|
||||
/* EOF */
|
@ -1,12 +1,10 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/utils.c
|
||||
* PURPOSE: Base set of functions for loading string resources
|
||||
* and message strings, and handle type identification.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Base set of functions for loading string resources
|
||||
* and message strings, and handle type identification.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
/* FIXME: Temporary HACK before we cleanly support UNICODE functions */
|
||||
@ -232,3 +230,5 @@ IsConsoleHandle(IN HANDLE hHandle)
|
||||
*/
|
||||
return GetConsoleMode(hHandle, &dwMode);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
@ -1,17 +1,17 @@
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* FILE: sdk/lib/conutils/utils.h
|
||||
* PURPOSE: Base set of functions for loading string resources
|
||||
* and message strings, and handle type identification.
|
||||
* PROGRAMMERS: - Hermes Belusca-Maito (for the library);
|
||||
* - All programmers who wrote the different console applications
|
||||
* from which I took those functions and improved them.
|
||||
* PROJECT: ReactOS Console Utilities Library
|
||||
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
||||
* PURPOSE: Base set of functions for loading string resources
|
||||
* and message strings, and handle type identification.
|
||||
* COPYRIGHT: Copyright 2017-2018 ReactOS Team
|
||||
* Copyright 2017-2018 Hermes Belusca-Maito
|
||||
*/
|
||||
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _UNICODE
|
||||
#error The ConUtils library at the moment only supports compilation with _UNICODE defined!
|
||||
#endif
|
||||
@ -57,4 +57,7 @@ IsConsoleHandle(IN HANDLE hHandle);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __UTILS_H__ */
|
||||
|
||||
/* EOF */
|
||||
|
Loading…
Reference in New Issue
Block a user