[SACDRV]: Last WIP pass at VTUTF8ChannelConsumeEscapeSequence. Document the last few commands, and comment the entire parser so that it makes sense (within MS's definition of making sense). The erase/clear commands need cleanup/implementation, will take a pass at those later.

svn path=/trunk/; revision=59827
This commit is contained in:
Alex Ionescu 2013-08-25 23:44:13 +00:00
parent 02ed8a9b93
commit 93883d01d6
2 changed files with 255 additions and 190 deletions

View file

@ -235,8 +235,10 @@ typedef enum _SAC_ANSI_COMMANDS
SacEraseScreen, SacEraseScreen,
SacSetCursorPosition, SacSetCursorPosition,
SacSetScrollRegion, SacSetScrollRegion,
SacSetBackgroundColor = 21, SacSetColors,
SacSetFontColor SacSetBackgroundColor,
SacSetFontColor,
SacSetColorsAndAttributes
} SAC_ANSI_COMMANDS; } SAC_ANSI_COMMANDS;
// //
@ -1325,3 +1327,154 @@ ChannelHasNewIBufferData(IN PSAC_CHANNEL Channel)
/* Return if there's any new data in the input buffer */ /* Return if there's any new data in the input buffer */
return Channel->ChannelHasNewIBufferData; return Channel->ChannelHasNewIBufferData;
} }
//
// FIXME: ANSI.H
//
//
// Source: http://en.wikipedia.org/wiki/ANSI_escape_code
//
typedef enum _VT_ANSI_ATTRIBUTES
{
//
// Attribute modifiers (mostly supported)
//
Normal,
Bold,
Faint,
Italic,
Underline,
SlowBlink,
FastBlink,
Inverse,
Conceal,
Strikethrough,
//
// Font selectors (not supported)
//
PrimaryFont,
AlternateFont1,
AlternateFont2,
AlternateFont3,
Alternatefont4,
AlteronateFont5,
AlteronateFont6,
AlternateFont7,
AlternatEfont8,
Alternatefont9,
//
// Additional attributes (not supported)
//
Fraktur,
DoubleUnderline,
//
// Attribute Un-modifiers (mostly supported)
//
BoldOff,
ItalicOff,
UnderlineOff,
BlinkOff,
Reserved,
InverseOff,
ConcealOff,
StrikethroughOff,
//
// Standard Text Color
//
SetColorStart,
SetColorBlack = SetColorStart,
SetColorRed,
SetColorGreen,
SetColorYellow,
SetColorBlue,
SetcolorMAgent,
SetColorCyan,
SetColorWhite,
SetColorMax = SetColorWhite,
//
// Extended Text Color (not supported)
//
SetColor256,
SeTextColorDefault,
//
// Standard Background Color
//
SetBackColorStart,
SetBackColorBlack = SetBackColorStart,
SetBackColorRed,
SetBackColorGreen,
SetBackColorYellow,
SetBackColorBlue,
SetBackcolorMAgent,
SetBackColorCyan,
SetBackColorWhite,
SetBackColorMax = SetBackColorWhite,
//
// Extended Background Color (not supported)
//
SetBackColor256,
SetBackColorDefault,
//
// Extra Attributes (not supported)
//
Reserved1,
Framed,
Encircled,
Overlined,
FramedOff,
OverlinedOff,
Reserved2,
Reserved3,
Reserved4,
Reserved5
//
// Ideograms (not supported)
//
} VT_ANSI_ATTRIBUTES;
//
// The following site is a good reference on VT100/ANSI escape codes
// http://www.termsys.demon.co.uk/vtansi.htm
//
#define VT_ANSI_ESCAPE L'\x1B'
#define VT_ANSI_COMMAND L'['
#define VT_ANSI_CURSOR_UP_CHAR L'A'
#define VT_ANSI_CURSOR_UP L"[A"
#define VT_ANSI_CURSOR_DOWN_CHAR L'B'
#define VT_ANSI_CURSOR_DOWN L"[B"
#define VT_ANSI_CURSOR_RIGHT_CHAR L'C'
#define VT_ANSI_CURSOR_RIGHT L"[C"
#define VT_ANSI_CURSOR_LEFT_CHAR L'D'
#define VT_ANSI_CURSOR_LEFT L"[D"
#define VT_ANSI_ERASE_LINE_CHAR L'K'
#define VT_ANSI_ERASE_END_LINE L"[K"
#define VT_ANSI_ERASE_START_LINE L"[1K"
#define VT_ANSI_ERASE_ENTIRE_LINE L"[2K"
#define VT_ANSI_ERASE_SCREEN_CHAR L'J'
#define VT_ANSI_ERASE_DOWN_SCREEN L"[J"
#define VT_ANSI_ERASE_UP_SCREEN L"[1J"
#define VT_ANSI_ERASE_ENTIRE_SCREEN L"[2J"
#define VT_ANSI_BACKTAB_CHAR L'Z'
#define VT_220_BACKTAB L"[0Z"
#define VT_ANSI_SET_ATTRIBUTE_CHAR L'm'
#define VT_ANSI_SEPARATOR_CHAR L';'
#define VT_ANSI_HVP_CURSOR_CHAR L'f'
#define VT_ANSI_CUP_CURSOR_CHAR L'H'
#define VT_ANSI_SCROLL_CHAR L'r'

View file

@ -15,156 +15,6 @@
CHAR IncomingUtf8ConversionBuffer[4]; CHAR IncomingUtf8ConversionBuffer[4];
WCHAR IncomingUnicodeValue; WCHAR IncomingUnicodeValue;
/* FUNCTIONS *****************************************************************/
//
// Source: http://en.wikipedia.org/wiki/ANSI_escape_code
//
typedef enum _VT_ANSI_ATTRIBUTES
{
//
// Attribute modifiers (mostly supported)
//
Normal,
Bold,
Faint,
Italic,
Underline,
SlowBlink,
FastBlink,
Inverse,
Conceal,
Strikethrough,
//
// Font selectors (not supported)
//
PrimaryFont,
AlternateFont1,
AlternateFont2,
AlternateFont3,
Alternatefont4,
AlteronateFont5,
AlteronateFont6,
AlternateFont7,
AlternatEfont8,
Alternatefont9,
//
// Additional attributes (not supported)
//
Fraktur,
DoubleUnderline,
//
// Attribute Un-modifiers (mostly supported)
//
BoldOff,
ItalicOff,
UnderlineOff,
BlinkOff,
Reserved,
InverseOff,
ConcealOff,
StrikethroughOff,
//
// Standard Text Color
//
SetColorStart,
SetColorBlack = SetColorStart,
SetColorRed,
SetColorGreen,
SetColorYellow,
SetColorBlue,
SetcolorMAgent,
SetColorCyan,
SetColorWhite,
SetColorMax = SetColorWhite,
//
// Extended Text Color (not supported)
//
SetColor256,
SeTextColorDefault,
//
// Standard Background Color
//
SetBackColorStart,
SetBackColorBlack = SetBackColorStart,
SetBackColorRed,
SetBackColorGreen,
SetBackColorYellow,
SetBackColorBlue,
SetBackcolorMAgent,
SetBackColorCyan,
SetBackColorWhite,
SetBackColorMax = SetBackColorWhite,
//
// Extended Background Color (not supported)
//
SetBackColor256,
SetBackColorDefault,
//
// Extra Attributes (not supported)
//
Reserved1,
Framed,
Encircled,
Overlined,
FramedOff,
OverlinedOff,
Reserved2,
Reserved3,
Reserved4,
Reserved5
//
// Ideograms (not supported)
//
} VT_ANSI_ATTRIBUTES;
//
// The following site is a good reference on VT100/ANSI escape codes
// http://www.termsys.demon.co.uk/vtansi.htm
//
#define VT_ANSI_ESCAPE L'\x1B'
#define VT_ANSI_COMMAND L'['
#define VT_ANSI_CURSOR_UP_CHAR L'A'
#define VT_ANSI_CURSOR_UP L"[A"
#define VT_ANSI_CURSOR_DOWN_CHAR L'B'
#define VT_ANSI_CURSOR_DOWN L"[B"
#define VT_ANSI_CURSOR_RIGHT_CHAR L'C'
#define VT_ANSI_CURSOR_RIGHT L"[C"
#define VT_ANSI_CURSOR_LEFT_CHAR L'D'
#define VT_ANSI_CURSOR_LEFT L"[D"
#define VT_ANSI_ERASE_LINE_CHAR L'K'
#define VT_ANSI_ERASE_END_LINE L"[K"
#define VT_ANSI_ERASE_START_LINE L"[1K"
#define VT_ANSI_ERASE_ENTIRE_LINE L"[2K"
#define VT_ANSI_ERASE_SCREEN_CHAR L'J'
#define VT_ANSI_ERASE_DOWN_SCREEN L"[J"
#define VT_ANSI_ERASE_UP_SCREEN L"[1J"
#define VT_ANSI_ERASE_ENTIRE_SCREEN L"[2J"
#define VT_ANSI_BACKTAB_CHAR L'Z'
#define VT_220_BACKTAB L"[0Z"
#define VT_ANSI_SET_ATTRIBUTE_CHAR L'm'
#define VT_ANSI_SEPARATOR_CHAR L';'
#define VT_ANSI_HVP_CURSOR_CHAR L'f'
#define VT_ANSI_CUP_CURSOR_CHAR L'H'
#define VT_ANSI_SCROLL_CHAR L'r'
SAC_STATIC_ESCAPE_STRING SacStaticEscapeStrings [] = SAC_STATIC_ESCAPE_STRING SacStaticEscapeStrings [] =
{ {
{ VT_ANSI_CURSOR_UP, 2, SacCursorUp }, { VT_ANSI_CURSOR_UP, 2, SacCursorUp },
@ -180,6 +30,16 @@ SAC_STATIC_ESCAPE_STRING SacStaticEscapeStrings [] =
{ VT_ANSI_ERASE_ENTIRE_SCREEN, 3, SacEraseScreen }, { VT_ANSI_ERASE_ENTIRE_SCREEN, 3, SacEraseScreen },
}; };
/* FUNCTIONS *****************************************************************/
FORCEINLINE
VOID
VTUTF8ChannelAssertCursor(IN PSAC_CHANNEL Channel)
{
ASSERT(Channel->CursorRow < SAC_VTUTF8_ROW_HEIGHT);
ASSERT(Channel->CursorCol < SAC_VTUTF8_COL_WIDTH);
}
BOOLEAN BOOLEAN
NTAPI NTAPI
VTUTF8ChannelScanForNumber(IN PWCHAR String, VTUTF8ChannelScanForNumber(IN PWCHAR String,
@ -225,16 +85,14 @@ VTUTF8ChannelProcessAttributes(
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
} }
FORCEINLINE
VOID
VTUTF8ChannelAssertCursor(IN PSAC_CHANNEL Channel)
{
ASSERT(Channel->CursorRow < SAC_VTUTF8_ROW_HEIGHT);
ASSERT(Channel->CursorCol < SAC_VTUTF8_COL_WIDTH);
}
// //
// Not a // This function is the guts of the sequences that SAC supports.
//
// It is written to conform to the way that Microsoft's SAC driver interprets
// the ANSI standard. If you want to extend and/or "fix" it, please use a flag
// that can be set in the Registry to enable "extended" ANSI support or etc...
//
// Hermes, I'm looking at you, buddy.
// //
ULONG ULONG
NTAPI NTAPI
@ -246,12 +104,18 @@ VTUTF8ChannelConsumeEscapeSequence(IN PSAC_CHANNEL Channel,
PSAC_CURSOR_DATA Cursor; PSAC_CURSOR_DATA Cursor;
ASSERT(String[0] == VT_ANSI_ESCAPE); ASSERT(String[0] == VT_ANSI_ESCAPE);
/* Microsoft's driver does this after the O(n) check below. Be smarter. */
if (String[1] != VT_ANSI_COMMAND) return 0;
/* Now that we know it's a valid command, look through the common cases */
for (i = 0; i < RTL_NUMBER_OF(SacStaticEscapeStrings); i++) for (i = 0; i < RTL_NUMBER_OF(SacStaticEscapeStrings); i++)
{ {
/* Check if an optimized sequence was detected */
if (!wcsncmp(String + 1, if (!wcsncmp(String + 1,
SacStaticEscapeStrings[i].Sequence, SacStaticEscapeStrings[i].Sequence,
SacStaticEscapeStrings[i].Size)) SacStaticEscapeStrings[i].Size))
{ {
/* Yep, return the right action, length, and set optionals to 1 */
Action = SacStaticEscapeStrings[i].Action; Action = SacStaticEscapeStrings[i].Action;
Result = SacStaticEscapeStrings[i].Size + 1; Result = SacStaticEscapeStrings[i].Size + 1;
Number = Number2 = Number3 = 1; Number = Number2 = Number3 = 1;
@ -259,10 +123,11 @@ VTUTF8ChannelConsumeEscapeSequence(IN PSAC_CHANNEL Channel,
} }
} }
if (String[1] != VT_ANSI_COMMAND) return 0; /* It's a more complex sequence, start parsing it */
Result = 0; Result = 0;
Sequence = String + 2; Sequence = String + 2;
/* First, check for the cursor sequences. This is useless due to above. */
switch (*Sequence) switch (*Sequence)
{ {
case VT_ANSI_CURSOR_UP_CHAR: case VT_ANSI_CURSOR_UP_CHAR:
@ -289,113 +154,154 @@ VTUTF8ChannelConsumeEscapeSequence(IN PSAC_CHANNEL Channel,
break; break;
} }
/* This must be a sequence starting with ESC[# */
if (!VTUTF8ChannelScanForNumber(Sequence, &Number)) return 0; if (!VTUTF8ChannelScanForNumber(Sequence, &Number)) return 0;
while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++;
/* Check if this is ESC[#m */
if (*Sequence == VT_ANSI_SET_ATTRIBUTE_CHAR) if (*Sequence == VT_ANSI_SET_ATTRIBUTE_CHAR)
{ {
/* Some attribute is being set, go over the ones we support */
switch (Number) switch (Number)
{ {
/* Make the font standard */
case Normal: case Normal:
Action = SacFontNormal; Action = SacFontNormal;
break; break;
/* Make the font bold */
case Bold: case Bold:
Action = SacFontBold; Action = SacFontBold;
break; break;
/* Make the font blink */
case SlowBlink: case SlowBlink:
Action = SacFontBlink; Action = SacFontBlink;
break; break;
/* Make the font colors inverted */
case Inverse: case Inverse:
Action = SacFontInverse; Action = SacFontInverse;
break; break;
/* Make the font standard intensity */
case BoldOff: case BoldOff:
Action = SacFontBoldOff; Action = SacFontBoldOff;
break; break;
/* Turn off blinking */
case BlinkOff: case BlinkOff:
Action = SacFontBlinkOff; Action = SacFontBlinkOff;
break; break;
/* Turn off inverted colors */
case InverseOff: case InverseOff:
Action = SacFontInverseOff; Action = SacFontInverseOff;
break; break;
/* Something else... */
default: default:
/* Is a background color being set? */
if ((Number < SetBackColorStart) || (Number > SetBackColorMax)) if ((Number < SetBackColorStart) || (Number > SetBackColorMax))
{ {
/* Nope... is it the foreground color? */
if ((Number < SetColorStart) || (Number > SetColorMax)) if ((Number < SetColorStart) || (Number > SetColorMax))
{ {
/* Nope. SAC expects no other attributes so bail out */
ASSERT(FALSE); ASSERT(FALSE);
return 0; return 0;
} }
/* Yep -- the number will tell us which */
Action = SacSetFontColor; Action = SacSetFontColor;
} }
else else
{ {
/* Yep -- the number will tell us which */
Action = SacSetBackgroundColor; Action = SacSetBackgroundColor;
} }
break; break;
} }
/* In all cases, we're done here */
goto ProcessString; goto ProcessString;
} }
/* The only allowed possibility now is ESC[#;# */
if (*Sequence != VT_ANSI_SEPARATOR_CHAR) return 0; if (*Sequence != VT_ANSI_SEPARATOR_CHAR) return 0;
Sequence++; Sequence++;
if (!VTUTF8ChannelScanForNumber(Sequence, &Number2)) return 0; if (!VTUTF8ChannelScanForNumber(Sequence, &Number2)) return 0;
while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++;
if (*Sequence == VT_ANSI_SET_ATTRIBUTE_CHAR) /* There's two valid forms accepted at this point: ESC[#;#m and ESC[#;#H */
switch (*Sequence)
{ {
Action = 20; /* This is ESC[#;#m -- used to set both colors at once */
case VT_ANSI_SET_ATTRIBUTE_CHAR:
Action = SacSetColors;
goto ProcessString; goto ProcessString;
}
if (*Sequence == VT_ANSI_CUP_CURSOR_CHAR) /* This is ESC[#;#H -- used to set the cursor position */
{ case VT_ANSI_CUP_CURSOR_CHAR:
Action = SacSetCursorPosition; Action = SacSetCursorPosition;
goto ProcessString; goto ProcessString;
}
if (*Sequence != VT_ANSI_SEPARATOR_CHAR) return 0;
/* Finally, this *could* be ESC[#;#; -- we'll keep parsing */
case VT_ANSI_SEPARATOR_CHAR:
Sequence++; Sequence++;
break;
if ((*Sequence == VT_ANSI_CUP_CURSOR_CHAR) || /* Abandon anything else */
(*Sequence == VT_ANSI_HVP_CURSOR_CHAR)) default:
{ return 0;
Action = SacSetCursorPosition;
goto ProcessString;
} }
if (*Sequence == VT_ANSI_SCROLL_CHAR) /* The SAC seems to accept a few more possibilities if a ';' follows... */
switch (*Sequence)
{ {
/* Both ESC[#;#;H and ESC[#;#;f are really the same command */
case VT_ANSI_CUP_CURSOR_CHAR:
case VT_ANSI_HVP_CURSOR_CHAR:
/* It's unclear why MS doesn't allow the HVP sequence on its own */
Action = SacSetCursorPosition;
goto ProcessString;
/* And this is the ESC[#;#;r command to set the scroll region... */
case VT_ANSI_SCROLL_CHAR:
/* Again, not clear why ESC[#;#r isn't supported */
Action = SacSetScrollRegion; Action = SacSetScrollRegion;
goto ProcessString; goto ProcessString;
/* Anything else must be ESC[#;#;# */
default:
break;
} }
/* Get the last "#" */
if (!VTUTF8ChannelScanForNumber(Sequence, &Number3)) return 0; if (!VTUTF8ChannelScanForNumber(Sequence, &Number3)) return 0;
while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++; while ((*Sequence >= L'0') && (*Sequence <= L'9')) Sequence++;
/* And now the only remaining possibility is ESC[#;#;#;m */
if (*Sequence == VT_ANSI_SET_ATTRIBUTE_CHAR) if (*Sequence == VT_ANSI_SET_ATTRIBUTE_CHAR)
{ {
Action = 23; /* Which sets both color and attributes in one command */
Action = SacSetColorsAndAttributes;
goto ProcessString; goto ProcessString;
} }
/* No other sequences supported */
return 0; return 0;
ProcessString: ProcessString:
/* Unless we got here from the optimized path, calculate the length */
if (!Result) Result = Sequence - String + 1; if (!Result) Result = Sequence - String + 1;
/* Get the current cell buffer */
Cursor = (PSAC_CURSOR_DATA)Channel->OBuffer; Cursor = (PSAC_CURSOR_DATA)Channel->OBuffer;
VTUTF8ChannelAssertCursor(Channel); VTUTF8ChannelAssertCursor(Channel);
/* Handle all the supported SAC ANSI commands */
switch (Action) switch (Action)
{ {
case SacCursorUp: case SacCursorUp:
@ -519,21 +425,26 @@ ProcessString:
break; break;
case SacEraseEndOfScreen: case SacEraseEndOfScreen:
ASSERT(FALSE); // todo
break; break;
case SacEraseStartOfScreen: case SacEraseStartOfScreen:
ASSERT(FALSE); // todo
break; break;
case SacEraseScreen: case SacEraseScreen:
ASSERT(FALSE); // todo
break; break;
case SacSetCursorPosition: case SacSetCursorPosition:
ASSERT(FALSE); // todo
break; break;
case SacSetScrollRegion: case SacSetScrollRegion:
ASSERT(FALSE); // todo
break; break;
case 20: case SacSetColors:
Channel->CursorColor = Number; Channel->CursorColor = Number;
Channel->CursorBackColor = Number2; Channel->CursorBackColor = Number2;
break; break;
@ -546,7 +457,7 @@ ProcessString:
Channel->CursorColor = Number; Channel->CursorColor = Number;
break; break;
case 23: case SacSetColorsAndAttributes:
Channel->CursorFlags = Number; Channel->CursorFlags = Number;
Channel->CursorColor = Number2; Channel->CursorColor = Number2;
Channel->CursorBackColor = Number3; Channel->CursorBackColor = Number3;
@ -555,6 +466,7 @@ ProcessString:
break; break;
} }
/* Return the length of the sequence */
return Result; return Result;
} }