Flush before accessing the console

Rather than flushing immediately after every write, only flush before
accessing the console.	This improves the speed, particularly for
programs that write character-by-character (which is basically every
program using Microsoft's printf).  Should it go wrong, there's a new
mode to restore the immediate flush: `\e[1+h`.
This commit is contained in:
Jason Hood 2017-12-22 18:08:51 +10:00
parent d04feca91c
commit edaf7ccace
4 changed files with 168 additions and 28 deletions

184
ANSI.c
View File

@ -152,7 +152,7 @@
remove wcstok, avoiding potential interference with the host;
similarly, use a private heap instead of malloc.
v1.80, 26 October to 21 December, 2017:
v1.80, 26 October to 22 December, 2017:
fix unloading;
revert back to (re)storing buffer cursor position;
increase cache to five handles;
@ -175,7 +175,8 @@
added the bright SGR colors, recognised the system indices;
added insert mode;
BS/CUB/HPB after wrap will move back to the previous line(s);
added DECOM, DECSTBM, SD & SU.
added DECOM, DECSTBM, SD & SU;
only flush before accessing the console, adding a mode to flush immediately.
*/
#include "ansicon.h"
@ -360,6 +361,24 @@ typedef BOOL (WINAPI *PHCSBIX)(
PHCSBIX GetConsoleScreenBufferInfoX, SetConsoleScreenBufferInfoX;
typedef struct _CONSOLE_FONT_INFOX {
ULONG cbSize;
DWORD nFont;
COORD dwFontSize;
UINT FontFamily;
UINT FontWeight;
WCHAR FaceName[LF_FACESIZE];
} CONSOLE_FONT_INFOX, *PCONSOLE_FONT_INFOX;
typedef BOOL (WINAPI *PHBCFIX)(
HANDLE hConsoleOutput,
BOOL bMaximumWindow,
PCONSOLE_FONT_INFOX lpConsoleCurrentFontEx
);
PHBCFIX SetCurrentConsoleFontX;
// Reduce verbosity.
#define CURPOS dwCursorPosition
#define ATTR Info.wAttributes
@ -391,6 +410,7 @@ typedef struct
{
SGR sgr, SaveSgr;
WORD SaveAttr;
BYTE fm; // flush mode
BYTE crm; // showing control characters?
COORD SavePos; // saved cursor position
COLORREF palette[16];
@ -1562,7 +1582,16 @@ void InterpretEscSeq( void )
case 'h': // SM - ESC[#h Set Mode
for (i = 0; i < es_argc; i++)
switch (es_argv[i])
if (suffix2 == '+')
{
switch (es_argv[i])
{
case 1: // ACFM
pState->fm = TRUE;
break;
}
}
else switch (es_argv[i])
{
case 3: // CRM
pState->crm = TRUE;
@ -1576,7 +1605,16 @@ void InterpretEscSeq( void )
case 'l': // RM - ESC[#l Reset Mode
for (i = 0; i < es_argc; i++)
switch (es_argv[i]) // CRM - ESC[3l is handled during parsing
if (suffix2 == '+')
{
switch (es_argv[i])
{
case 1: // ACFM
pState->fm = FALSE;
break;
}
}
else switch (es_argv[i]) // CRM - ESC[3l is handled during parsing
{
case 4: // IRM
im = FALSE;
@ -1932,6 +1970,7 @@ ParseAndPrintString( HANDLE hDev,
if (hDev != hConOut) // reinit if device has changed
{
FlushBuffer();
hConOut = hDev;
state = 1;
im = shifted = G0_special = FALSE;
@ -2221,7 +2260,7 @@ ParseAndPrintString( HANDLE hDev,
state = 1;
}
}
FlushBuffer();
if (pState->fm) FlushBuffer();
if (lpNumberOfBytesWritten != NULL)
*lpNumberOfBytesWritten = nNumberOfBytesToWrite - i;
return (i == 0);
@ -2916,7 +2955,11 @@ BOOL IsConsoleHandle( HANDLE h )
BOOL
WINAPI MySetConsoleMode( HANDLE hCon, DWORD mode )
{
BOOL rc = SetConsoleMode( hCon, mode );
BOOL rc;
FlushBuffer();
rc = SetConsoleMode( hCon, mode );
if (rc)
{
int c;
@ -2925,6 +2968,8 @@ WINAPI MySetConsoleMode( HANDLE hCon, DWORD mode )
// The mode is associated with the buffer, not the handle.
GetConsoleMode( cache[c].h, &cache[c].mode );
}
if (hCon == hConOut)
awm = (mode & ENABLE_WRAP_AT_EOL_OUTPUT) ? TRUE : FALSE;
}
return rc;
}
@ -3256,6 +3301,64 @@ WINAPI MyCreateConsoleScreenBuffer( DWORD dwDesiredAccess, DWORD dwShareMode,
}
//-----------------------------------------------------------------------------
// My...
// Flush the buffer before accessing the console.
//-----------------------------------------------------------------------------
#define FLUSH2( func, arg2 ) \
BOOL WINAPI My##func( HANDLE a1, arg2 a2 )\
{ FlushBuffer(); return func( a1, a2 ); }
#define FLUSH2X( func, arg2 ) \
BOOL WINAPI My##func##Ex( HANDLE a1, arg2 a2 )\
{ FlushBuffer(); return func##X( a1, a2 ); }
#define FLUSH3( func, arg2, arg3 ) \
BOOL WINAPI My##func( HANDLE a1, arg2 a2, arg3 a3 )\
{ FlushBuffer(); return func( a1, a2, a3 ); }
#define FLUSH3X( func, arg2, arg3 ) \
BOOL WINAPI My##func##Ex( HANDLE a1, arg2 a2, arg3 a3 )\
{ FlushBuffer(); return func##X( a1, a2, a3 ); }
#define FLUSH4( func, arg2, arg3, arg4 ) \
BOOL WINAPI My##func( HANDLE a1, arg2 a2, arg3 a3, arg4 a4 )\
{ FlushBuffer(); return func( a1, a2, a3, a4 ); }
#define FLUSH5( func, arg2, arg3, arg4, arg5 ) \
BOOL WINAPI My##func( HANDLE a1, arg2 a2, arg3 a3, arg4 a4, arg5 a5 )\
{ FlushBuffer(); return func( a1, a2, a3, a4, a5 ); }
FLUSH5( FillConsoleOutputAttribute, WORD, DWORD, COORD, LPDWORD )
FLUSH5( FillConsoleOutputCharacterA, CHAR, DWORD, COORD, LPDWORD )
FLUSH5( FillConsoleOutputCharacterW, WCHAR, DWORD, COORD, LPDWORD )
FLUSH2( GetConsoleScreenBufferInfo, PCONSOLE_SCREEN_BUFFER_INFO )
FLUSH2X( GetConsoleScreenBufferInfo, PCONSOLE_SCREEN_BUFFER_INFOX )
FLUSH5( ReadFile, LPVOID, DWORD, LPDWORD, LPOVERLAPPED )
FLUSH5( ReadConsoleA, LPVOID, DWORD, LPDWORD, LPVOID )
FLUSH5( ReadConsoleW, LPVOID, DWORD, LPDWORD, LPVOID )
FLUSH4( ReadConsoleInputA, PINPUT_RECORD, DWORD, LPDWORD )
FLUSH4( ReadConsoleInputW, PINPUT_RECORD, DWORD, LPDWORD )
FLUSH5( ReadConsoleOutputA, PCHAR_INFO, COORD, COORD, PSMALL_RECT )
FLUSH5( ReadConsoleOutputW, PCHAR_INFO, COORD, COORD, PSMALL_RECT )
FLUSH5( ReadConsoleOutputAttribute, LPWORD, DWORD, COORD, LPDWORD )
FLUSH5( ReadConsoleOutputCharacterA, LPSTR, DWORD, COORD, LPDWORD )
FLUSH5( ReadConsoleOutputCharacterW, LPWSTR, DWORD, COORD, LPDWORD )
FLUSH5( ScrollConsoleScreenBufferA, SMALL_RECT*,SMALL_RECT*, COORD, CHAR_INFO* )
FLUSH5( ScrollConsoleScreenBufferW, SMALL_RECT*,SMALL_RECT*, COORD, CHAR_INFO* )
FLUSH2( SetConsoleCursorPosition, COORD )
FLUSH2( SetConsoleScreenBufferSize, COORD )
FLUSH2( SetConsoleTextAttribute, WORD )
FLUSH3( SetConsoleWindowInfo, BOOL, const SMALL_RECT* )
FLUSH3X( SetCurrentConsoleFont, BOOL, PCONSOLE_FONT_INFOX )
FLUSH5( WriteConsoleOutputA, const CHAR_INFO*, COORD, COORD, PSMALL_RECT )
FLUSH5( WriteConsoleOutputW, const CHAR_INFO*, COORD, COORD, PSMALL_RECT )
FLUSH5( WriteConsoleOutputAttribute, const WORD*, DWORD, COORD, LPDWORD )
FLUSH5( WriteConsoleOutputCharacterA, LPCSTR, DWORD, COORD, LPDWORD )
FLUSH5( WriteConsoleOutputCharacterW, LPCWSTR, DWORD, COORD, LPDWORD )
// ========== Environment variable
void set_ansicon( PCONSOLE_SCREEN_BUFFER_INFO pcsbi )
@ -3336,27 +3439,55 @@ WINAPI MyGetEnvironmentVariableW( LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize )
// ========== Initialisation
#define HOOK( dll, name ) { dll, #name, (PROC)My##name, NULL, NULL, NULL }
HookFn Hooks[] = {
// These two are expected first!
{ APILibraryLoader, "LoadLibraryA", (PROC)MyLoadLibraryA, NULL, NULL, NULL },
{ APILibraryLoader, "LoadLibraryW", (PROC)MyLoadLibraryW, NULL, NULL, NULL },
{ APIProcessThreads, "CreateProcessA", (PROC)MyCreateProcessA, NULL, NULL, NULL },
{ APIProcessThreads, "CreateProcessW", (PROC)MyCreateProcessW, NULL, NULL, NULL },
{ APIProcessEnvironment, "GetEnvironmentVariableA", (PROC)MyGetEnvironmentVariableA, NULL, NULL, NULL },
{ APIProcessEnvironment, "GetEnvironmentVariableW", (PROC)MyGetEnvironmentVariableW, NULL, NULL, NULL },
{ APILibraryLoader, "GetProcAddress", (PROC)MyGetProcAddress, NULL, NULL, NULL },
{ APILibraryLoader, "LoadLibraryExA", (PROC)MyLoadLibraryExA, NULL, NULL, NULL },
{ APILibraryLoader, "LoadLibraryExW", (PROC)MyLoadLibraryExW, NULL, NULL, NULL },
{ APIConsole, "SetConsoleMode", (PROC)MySetConsoleMode, NULL, NULL, NULL },
{ APIConsole, "WriteConsoleA", (PROC)MyWriteConsoleA, NULL, NULL, NULL },
{ APIConsole, "WriteConsoleW", (PROC)MyWriteConsoleW, NULL, NULL, NULL },
{ APIFile, "WriteFile", (PROC)MyWriteFile, NULL, NULL, NULL },
{ APIKernel, "_lwrite", (PROC)My_lwrite, NULL, NULL, NULL },
{ APIProcessThreads, "ExitProcess", (PROC)MyExitProcess, NULL, NULL, NULL },
{ APILibraryLoader, "FreeLibrary", (PROC)MyFreeLibrary, NULL, NULL, NULL },
{ APIFile, "CreateFileA", (PROC)MyCreateFileA, NULL, NULL, NULL },
{ APIFile, "CreateFileW", (PROC)MyCreateFileW, NULL, NULL, NULL },
{ APIKernel, "CreateConsoleScreenBuffer", (PROC)MyCreateConsoleScreenBuffer, NULL, NULL, NULL },
HOOK( APILibraryLoader, LoadLibraryA ),
HOOK( APILibraryLoader, LoadLibraryW ),
HOOK( APIProcessThreads, CreateProcessA ),
HOOK( APIProcessThreads, CreateProcessW ),
HOOK( APIProcessEnvironment, GetEnvironmentVariableA ),
HOOK( APIProcessEnvironment, GetEnvironmentVariableW ),
HOOK( APILibraryLoader, GetProcAddress ),
HOOK( APILibraryLoader, LoadLibraryExA ),
HOOK( APILibraryLoader, LoadLibraryExW ),
HOOK( APIConsole, SetConsoleMode ),
HOOK( APIConsole, WriteConsoleA ),
HOOK( APIConsole, WriteConsoleW ),
HOOK( APIFile, WriteFile ),
HOOK( APIKernel, _lwrite ),
HOOK( APIProcessThreads, ExitProcess ),
HOOK( APILibraryLoader, FreeLibrary ),
HOOK( APIFile, CreateFileA ),
HOOK( APIFile, CreateFileW ),
HOOK( APIKernel, CreateConsoleScreenBuffer ),
HOOK( APIKernel, FillConsoleOutputAttribute ),
HOOK( APIKernel, FillConsoleOutputCharacterA ),
HOOK( APIKernel, FillConsoleOutputCharacterW ),
HOOK( APIKernel, GetConsoleScreenBufferInfo ),
HOOK( APIKernel, GetConsoleScreenBufferInfoEx ),
HOOK( APIFile, ReadFile ),
HOOK( APIConsole, ReadConsoleA ),
HOOK( APIConsole, ReadConsoleW ),
HOOK( APIConsole, ReadConsoleInputA ),
HOOK( APIConsole, ReadConsoleInputW ),
HOOK( APIKernel, ReadConsoleOutputA ),
HOOK( APIKernel, ReadConsoleOutputW ),
HOOK( APIKernel, ReadConsoleOutputAttribute ),
HOOK( APIKernel, ReadConsoleOutputCharacterA ),
HOOK( APIKernel, ReadConsoleOutputCharacterW ),
HOOK( APIKernel, ScrollConsoleScreenBufferA ),
HOOK( APIKernel, ScrollConsoleScreenBufferW ),
HOOK( APIKernel, SetConsoleCursorPosition ),
HOOK( APIKernel, SetConsoleScreenBufferSize ),
HOOK( APIKernel, SetConsoleTextAttribute ),
HOOK( APIKernel, SetConsoleWindowInfo ),
HOOK( APIKernel, WriteConsoleOutputA ),
HOOK( APIKernel, WriteConsoleOutputW ),
HOOK( APIKernel, WriteConsoleOutputAttribute ),
HOOK( APIKernel, WriteConsoleOutputCharacterA ),
HOOK( APIKernel, WriteConsoleOutputCharacterW ),
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@ -3421,6 +3552,8 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
hKernel, "GetConsoleScreenBufferInfoEx" );
SetConsoleScreenBufferInfoX = (PHCSBIX)GetProcAddress(
hKernel, "SetConsoleScreenBufferInfoEx" );
SetCurrentConsoleFontX = (PHBCFIX)GetProcAddress(
hKernel, "SetCurrentConsoleFontEx" );
*logstr = '\0';
GetEnvironmentVariable( L"ANSICON_LOG", logstr, lenof(logstr) );
@ -3453,6 +3586,7 @@ BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved )
}
else if (dwReason == DLL_PROCESS_DETACH)
{
FlushBuffer();
if (lpReserved == NULL)
{
DEBUGSTR( 1, "Unloading" );

View File

@ -91,7 +91,7 @@
use -pu to unload from the parent.
*/
#define PDATE L"21 December, 2017"
#define PDATE L"22 December, 2017"
#include "ansicon.h"
#include "version.h"

View File

@ -160,6 +160,8 @@ Sequences Recognised
\e[21t xterm: Report window's title
\e[s ANSI.SYS: Save Cursor Position
\e[u ANSI.SYS: Restore Cursor Position
\e[1+h ACFM Flush Mode (flush immediately)
\e[1+l ACFM Flush Mode (flush when necessary)
BEL BEL Bell
\e[#Z CBT Cursor Backward Tabulation
\e[#G CHA Cursor Character Absolute
@ -317,7 +319,7 @@ Version History
Legend: + added, - bug-fixed, * changed.
1.80 - 21 December, 2017:
1.80 - 22 December, 2017:
- fix unloading;
- fix -e et al when redirecting to CON;
- hook CreateFile and CreateConsoleScreenBuffer to force read/write access
@ -332,6 +334,8 @@ Version History
* escaped control characters will display the control;
* change the graphics SCAN characters to their Unicode equivalents;
* BS/CUB/HVP after wrap will move back to the previous line(s);
* improve speed by only flushing when necessary, adding a mode to restore
flushing immediately.
+ use the system default sound for the bell;
+ added Play Sound DECPS;
+ added '+' intermediate byte to use the buffer, rather than the window;
@ -571,4 +575,4 @@ Distribution
==============================
Jason Hood, 21 December, 2017.
Jason Hood, 22 December, 2017.

View File

@ -165,6 +165,8 @@ H set tab stop
(0 select the DEC Special Graphics Character Set
(B select ASCII
[1+h flush immediately on write
[1+l flush only when necessary
[3h display control characters (LF is also performed)
[3l perform control functions (the only such recognised during above)
[4h insert characters