Last active
September 1, 2023 04:09
-
-
Save M-griffin/16c0f85f3e2e8bb7395d to your computer and use it in GitHub Desktop.
Terminal Control Sequence Validator and Splitter.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Terminal Control Sequence Parser | |
* (c) Michael Griffin <[email protected]> | |
* 12/27/2014 | |
* Runs through passed string data to parse text and control sequences | |
* Handle the most basic terminal and a majority of Xterm Control Sequences. | |
* Window Text and String sequences are not handeled. | |
* | |
* The job of this class is to seperate text and control sequences, | |
* When control sequences are present they are parameterized into a vector | |
* with the sequence terminator as the first parameter and following | |
* paramerters incrimented to the next slot in the vector. | |
* | |
* ex.. ESC[0;21;30m would be broken up into: | |
* [0] m | |
* [1] 0 | |
* [2] 21 | |
* [3] 30 | |
* | |
* Then passed to the Screen Parser for drawing to the screen. | |
*/ | |
#include <iostream> | |
#include <string> | |
#include <vector> | |
#include <sstream> | |
class SequenceParser | |
{ | |
public: | |
// Instaniate the Singleton | |
static SequenceParser* Instance() | |
{ | |
if(globalInstance == 0) | |
{ | |
globalInstance = new SequenceParser(); | |
return globalInstance; | |
} | |
return globalInstance; | |
} | |
// Release And Clear the Singleton | |
static void ReleaseInstance() | |
{ | |
if(globalInstance != 0) | |
{ | |
delete globalInstance; | |
globalInstance = 0; | |
} | |
return; | |
} | |
// Parser String data for ESC Sequence. | |
void ProcessSequence(std::string inputString); | |
private: | |
// Sequence Parser State | |
enum | |
{ | |
SEQ_NORMAL = 0, // Normal Text Data | |
SEQ_START = 1, // Start of ESC Sequence | |
SEQ_PROCESSING = 2, // Processing for Complete Sequence | |
SEQ_DONE = 3, // ESC Sequence Completed OK. | |
SEQ_ERROR = 4 // Bad Sequence, Kill it! | |
}; | |
int sequenceState; | |
unsigned | |
char sequence; | |
int parameter; | |
bool foundSequence; | |
bool foundParameters; | |
bool invalidSequence; | |
bool sequenceCompleted; | |
int sequenceLevel; | |
void ProcessLevel0(); | |
void ProcessLevel1(); | |
void ProcessLevel2(); | |
void ValidateSequence(); | |
// Holds the interm data while we build the sequence, | |
// This is needed if inputString doesn't have a complete sequence | |
// Then we need to append so that the string will have the | |
// Original first half of the already parsed sequence. | |
std::string sequenceBuilder; | |
//Holds the breakdown of the entire sequence | |
std::vector<int> params; | |
// This string contains normal data passed through the sequence | |
// Parser, At the end of a processing loop, this data is passed | |
// for writting to the screen. | |
std::string validOutputData; | |
std::string::size_type | |
escapePosition; | |
static SequenceParser* globalInstance; | |
SequenceParser(); | |
~SequenceParser(); | |
SequenceParser(const SequenceParser&); | |
SequenceParser& operator=(const SequenceParser&); | |
}; | |
//Setup the Class Type | |
typedef SequenceParser TheSequenceParser; | |
// Init the Global Instance | |
SequenceParser* SequenceParser::globalInstance = 0; | |
// Initalize Class Variables | |
SequenceParser::SequenceParser() : | |
sequenceState(SEQ_NORMAL), | |
sequence(0), | |
parameter(0), | |
foundSequence(false), | |
foundParameters(false), | |
invalidSequence(false), | |
sequenceCompleted(false), | |
sequenceLevel(0) | |
{ } | |
SequenceParser::~SequenceParser() | |
{ | |
std::vector<int>().swap(params); // Clear | |
std::cout << "SequencePasser Destructor" << std::endl; | |
} | |
/* | |
* Level 0 Parsing check for Start of CSI or Alternate ESC Sequecnes | |
* Supported in Xterm that a server might send. | |
* Switch Statement catches the Start of a Valid Sequence. | |
*/ | |
void SequenceParser::ProcessLevel0() | |
{ | |
switch (sequence) | |
{ | |
case '[': // Control Sequence Introducer ( CSI is 0x9b). | |
break; | |
// Xterm Sequences Not implimented, pass through | |
case ' ': | |
//ESC SP F 7-bit controls (S7C1T). | |
//ESC SP G 8-bit controls (S8C1T). | |
//ESC SP L Set ANSI conformance level 1 (dpANS X3.134.1). | |
//ESC SP M Set ANSI conformance level 2 (dpANS X3.134.1). | |
//ESC SP N Set ANSI conformance level 3 (dpANS X3.134.1). | |
case '#': | |
//ESC # 3 DEC double-height line, top half (DECDHL). | |
//ESC # 4 DEC double-height line, bottom half (DECDHL). | |
//ESC # 5 DEC single-width line (DECSWL). | |
//ESC # 6 DEC double-width line (DECDWL). | |
//ESC # 8 DEC Screen Alignment Test (DECALN). | |
case '%': | |
//ESC % @ Select default character set. That is ISO 8859-1 (ISO 2022). | |
//ESC % G Select UTF-8 character set (ISO 2022). | |
case '(': | |
//ESC ( C | |
//C = U → CP437 Character Set. (Not shown on most! MF) | |
//C = 0 → DEC Special Character and Line Drawing Set. | |
//C = < → DEC Supplementary (VT200). | |
//C = % 5 → DEC Supplementary Graphics (VT300). | |
//C = > → DEC Technical (VT300). | |
//C = A → United Kingdom (UK). | |
//C = B → United States (USASCII). | |
//C = 4 → Dutch. | |
//C = C or 5 → Finnish. | |
//C = R or f → French. | |
//C = Q or 9 → French Canadian (VT200, VT300). | |
//C = K → German. | |
//C = Y → Italian. | |
//C = ` , E or 6 → Norwegian/Danish. | |
//C = % 6 → Portuguese (VT300). | |
//C = Z → Spanish. | |
//C = H or 7 → Swedish. | |
//C = = → Swiss. | |
case ')': | |
//Designate G1 Character Set (ISO 2022, VT100). | |
//The same character sets apply as for ESC ( C. | |
case '?': | |
// Set/Reset Modes | |
// Invalid, should have CSI = ESC[ preceeding ? | |
// Xterm C1 (8-Bit) Control Characters | |
case 'D': // Index ( IND is 0x84). | |
case 'E': // Next Line ( NEL is 0x85). | |
case 'H': // Tab Set ( HTS is 0x88). | |
case 'M': // Reverse Index ( RI is 0x8d). | |
case 'N': // Single Shift Select of G2 Character Set ( SS2 is 0x8e). This affects next character only. | |
case 'O': // Single Shift Select of G3 Character Set ( SS3 is 0x8f). This affects next character only. | |
case 'P': // Device Control String ( DCS is 0x90). | |
case 'V': // Start of Guarded Area ( SPA is 0x96). | |
case 'W': // End of Guarded Area ( EPA is 0x97). | |
case 'X': // Start of String ( SOS is 0x98). | |
case 'Z': // Return Terminal ID (DECID is 0x9a). Obsolete form of CSI c (DA). | |
case ']': // Operating System Command ( OSC is 0x9d). | |
case '^': // Privacy Message ( PM is 0x9e). | |
case '_': // Application Program Command ( APC is 0x9f). | |
case '\\': // String Terminator ( ST is 0x9c). | |
case '*': | |
//ESC * C Designate G2 Character Set (ISO 2022, VT220). | |
//The same character sets apply as for ESC ( C. | |
case '+': | |
//ESC + C Designate G3 Character Set (ISO 2022, VT220). | |
//The same character sets apply as for ESC ( C. | |
case '-': | |
//ESC - C Designate G1 Character Set (VT300). | |
//The same character sets apply as for ESC ( C. | |
case '.': | |
//ESC . C Designate G2 Character Set (VT300). | |
//The same character sets apply as for ESC ( C. | |
case '/': | |
//ESC / C Designate G3 Character Set (VT300). | |
//These work for 96-character sets only. | |
//C = A → ISO Latin-1 Supplemental. | |
case '6': // ESC 6 Back Index (DECBI), VT420 and up. | |
case '7': // ESC 7 Save Cursor (DECSC). | |
case '8': // ESC 8 Restore Cursor (DECRC). | |
case '9': // ESC 9 Forward Index (DECFI), VT420 and up. | |
case '=': // ESC = Application Keypad (DECKPAM). | |
case '>': // ESC > Normal Keypad (DECKPNM). | |
case 'F': // ESC F Cursor to lower left corner of screen. This is enabled by the hpLowerleftBugCompat resource. | |
case 'c': // ESC c Full Reset (RIS). | |
case 'l': // ESC l Memory Lock (per HP terminals). Locks memory above the cursor. | |
case 'm': // ESC m Memory Unlock (per HP terminals). | |
case 'n': // ESC n Invoke the G2 Character Set as GL (LS2). | |
case 'o': // ESC o Invoke the G3 Character Set as GL (LS3). | |
case '|': // ESC | Invoke the G3 Character Set as GR (LS3R). | |
case '}': // ESC } Invoke the G2 Character Set as GR (LS2R). | |
case '~': // ESC ~ Invoke the G1 Character Set as GR (LS1R). | |
case '\0': // Catch any NULL characters after ESC | |
case '\x1b': // catch any double ESC's from bad servers | |
invalidSequence = true; | |
break; | |
default: | |
// Nothing Matched, Shouldn't get here. | |
invalidSequence = true; | |
#ifdef _DEBUG | |
std::cout << "CSI parser exception: received ESC: " | |
<< sequence << std::endl; | |
#endif | |
break; | |
} | |
} | |
/* | |
* Level 1 Parsing Comes After ESC[ = CSI. | |
* Numbers and Seperators are found in the middle of sequences as Parameters | |
* Switch Statement catch the end of a Valid Sequence. | |
* | |
* Any nonSupported sequences can have certain charactes after the CSI | |
* and These are parsed so that they are skipped and marked Invalid. | |
*/ | |
void SequenceParser::ProcessLevel1() | |
{ | |
// If we get here, only valid Sequences are ESC [ Then next Character. | |
// First Check for Parameters in Sequence | |
if (std::isdigit(sequence)) // Mark for Parameter | |
{ | |
// Contine to next sequence | |
#ifdef _DEBUG | |
std::cout << "Is a Number: " << sequence << std::endl; | |
#endif | |
return; | |
} | |
else | |
if (sequence == ';') // Mark for Multi-Parameter | |
{ | |
// Continue to Next Sequence | |
#ifdef _DEBUG | |
std::cout << "Is a Seperator: " << sequence << std::endl; | |
#endif | |
return; | |
} | |
// Catch Valid ESC Sequence Terminators. | |
switch (sequence) | |
{ | |
case '@': // Insert P s (Blank) Character(s) (default = 1) (ICH). | |
case 'A': // Cursor Up P s Times (default = 1) (CUU) | |
case 'B': // Cursor Down P s Times (default = 1) (CUD) | |
case 'C': // Cursor Forward P s Times (default = 1) (CUF) | |
case 'D': // Cursor Backward P s Times (default = 1) (CUB) | |
case 'E': // Cursor Next Line P s Times (default = 1) (CNL) | |
case 'F': // Cursor Preceding Line P s Times (default = 1) (CPL) | |
case 'G': // Cursor Character Absolute [column] (default = [row,1]) (CHA) | |
case 'H': // Cursor Position [row;column] (default = [1,1]) (CUP) | |
case 'I': // Cursor Forward Tabulation P s tab stops (default = 1) (CHT). | |
case 'J': | |
// Erase in Display (ED). - DECSED has ESC[?J | |
//P s = 0 → Erase Below (default). | |
//P s = 1 → Erase Above. | |
//P s = 2 → Erase All. | |
//P s = 3 → Erase Saved Lines (xterm). | |
case 'K': | |
// Erase in Line (EL). - DECSED has ESC[?K | |
//P s = 0 → Erase to Right (default). | |
//P s = 1 → Erase to Left. | |
//P s = 2 → Erase All. | |
case 'L': // Insert P s Line(s) (default = 1) (IL). | |
case 'M': // Delete P s Line(s) (default = 1) (DL). | |
case 'P': // Delete P s Character(s) (default = 1) (DCH). | |
case 'S': // Scroll up P s lines (default = 1) (SU). | |
case 'T': // Scroll down P s lines (default = 1) (SD). | |
case 'X': // Erase P s Character(s) (default = 1) (ECH). | |
case 'Z': // Cursor Backward Tabulation P s tab stops (default = 1) (CBT). | |
case '`': // Character Position Absolute [column] (default = [row,1]) (HPA). | |
case 'a': // Character Position Relative [columns] (default = [row,col+1]) (HPR). | |
case 'b': // Repeat the preceding graphic character P s times (REP). | |
case 'c': | |
// Send Device Attributes (Primary DA). | |
//P s = 0 or omitted → request attributes from terminal. The response depends on the decTerminalID resource setting. | |
//→ CSI ? 1 ; 2 c (‘‘VT100 with Advanced Video Option’’) | |
//→ CSI ? 1 ; 0 c (‘‘VT101 with No Options’’) | |
//→ CSI ? 6 c (‘‘VT102’’) | |
//→ CSI ? 6 2 ; P s c (‘‘VT220’’) | |
//→ CSI ? 6 3 ; P s c (‘‘VT320’’) | |
//→ CSI ? 6 4 ; P s c (‘‘VT420’’) | |
// The VT100-style response parameters do not mean anything by themselves. VT220 (and higher) parameters do, telling the host what features the terminal supports: | |
//P s = 1 → 132-columns. | |
//P s = 2 → Printer. | |
//P s = 3 → ReGIS graphics. | |
//P s = 4 → Sixel graphics. | |
//P s = 6 → Selective erase. | |
//P s = 8 → User-defined keys. | |
//P s = 9 → National Replacement Character sets. | |
//P s = 1 5 → Technical characters. | |
//P s = 1 8 → User windows. | |
//P s = 2 1 → Horizontal scrolling. | |
//P s = 2 2 → ANSI color, e.g., VT525. | |
//P s = 2 9 → ANSI text locator (i.e., DEC Locator mode). | |
case 'd': // Line Position Absolute [row] (default = [1,column]) (VPA). | |
case 'e': // Line Position Relative [rows] (default = [row+1,column]) (VPR). | |
case 'f': // equivalent to 'H' | |
case 'g': // Tab Clear (TBC). | |
case 'h': | |
// Set Mode (SM). | |
//P s = 2 → Keyboard Action Mode (AM). | |
//P s = 4 → Insert Mode (IRM). | |
//P s = 1 2 → Send/receive (SRM). | |
//P s = 2 0 → Automatic Newline (LNM). | |
// DEC Private Mode Set (DECSET). ESC [ ? h | |
//P s = 1 → Application Cursor Keys (DECCKM). | |
//P s = 2 → Designate USASCII for character sets G0-G3 (DECANM), and set VT100 mode. | |
//P s = 3 → 132 Column Mode (DECCOLM). | |
//P s = 4 → Smooth (Slow) Scroll (DECSCLM). | |
//P s = 5 → Reverse Video (DECSCNM). | |
//P s = 6 → Origin Mode (DECOM). | |
//P s = 7 → Wraparound Mode (DECAWM). | |
//P s = 8 → Auto-repeat Keys (DECARM). | |
//P s = 9 → Send Mouse X & Y on button press. See the section Mouse Tracking. This is the X10 xterm mouse protocol. | |
//P s = 1 0 → Show toolbar (rxvt). | |
//P s = 1 2 → Start Blinking Cursor (att610). | |
//P s = 1 8 → Print form feed (DECPFF). | |
//P s = 1 9 → Set print extent to full screen (DECPEX). | |
//P s = 2 5 → Show Cursor (DECTCEM). | |
//P s = 3 0 → Show scrollbar (rxvt). | |
//P s = 3 5 → Enable font-shifting functions (rxvt). | |
//P s = 3 8 → Enter Tektronix Mode (DECTEK). | |
//P s = 4 0 → Allow 80 → 132 Mode. | |
//P s = 4 1 → more(1) fix (see curses resource). | |
//P s = 4 2 → Enable National Replacement Character sets (DECNRCM). | |
//P s = 4 4 → Turn On Margin Bell. | |
//P s = 4 5 → Reverse-wraparound Mode. | |
//P s = 4 6 → Start Logging. This is normally disabled by a compile-time option. | |
//P s = 4 7 → Use Alternate Screen Buffer. (This may be disabled by the titeInhibit resource). | |
//P s = 6 6 → Application keypad (DECNKM). | |
//P s = 6 7 → Backarrow key sends backspace (DECBKM). | |
//P s = 6 9 → Enable left and right margin mode (DECLRMM), VT420 and up. | |
//P s = 9 5 → Do not clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up. | |
//P s = 1 0 0 0 → Send Mouse X & Y on button press and release. See the section Mouse Tracking. This is the X11 xterm mouse protocol. | |
//P s = 1 0 0 1 → Use Hilite Mouse Tracking. | |
//P s = 1 0 0 2 → Use Cell Motion Mouse Tracking. | |
//P s = 1 0 0 3 → Use All Motion Mouse Tracking. | |
//P s = 1 0 0 4 → Send FocusIn/FocusOut events. | |
//P s = 1 0 0 5 → Enable UTF-8 Mouse Mode. | |
//P s = 1 0 0 6 → Enable SGR Mouse Mode. | |
//P s = 1 0 0 7 → Enable Alternate Scroll Mode. | |
//P s = 1 0 1 0 → Scroll to bottom on tty output (rxvt). | |
//P s = 1 0 1 1 → Scroll to bottom on key press (rxvt). | |
//P s = 1 0 1 5 → Enable urxvt Mouse Mode. | |
//P s = 1 0 3 4 → Interpret "meta" key, sets eighth bit. (enables the eightBitInput resource). | |
//P s = 1 0 3 5 → Enable special modifiers for Alt and NumLock keys. (This enables the numLock resource). | |
//P s = 1 0 3 6 → Send ESC when Meta modifies a key. (This enables the metaSendsEscape resource). | |
//P s = 1 0 3 7 → Send DEL from the editing-keypad Delete key. | |
//P s = 1 0 3 9 → Send ESC when Alt modifies a key. (This enables the altSendsEscape resource). | |
//P s = 1 0 4 0 → Keep selection even if not highlighted. (This enables the keepSelection resource). | |
//P s = 1 0 4 1 → Use the CLIPBOARD selection. (This enables the selectToClipboard resource). | |
//P s = 1 0 4 2 → Enable Urgency window manager hint when Control-G is received. (This enables the bellIsUrgent resource). | |
//P s = 1 0 4 3 → Enable raising of the window when Control-G is received. (enables the popOnBell resource). | |
//P s = 1 0 4 7 → Use Alternate Screen Buffer. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 8 → Save cursor as in DECSC. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 9 → Save cursor as in DECSC and use Alternate Screen Buffer, clearing it first. (This may be disabled by the titeInhibit resource). This combines the effects of the 1 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based applications rather than the 4 7 mode. | |
//P s = 1 0 5 0 → Set terminfo/termcap function-key mode. | |
//P s = 1 0 5 1 → Set Sun function-key mode. | |
//P s = 1 0 5 2 → Set HP function-key mode. | |
//P s = 1 0 5 3 → Set SCO function-key mode. | |
//P s = 1 0 6 0 → Set legacy keyboard emulation (X11R6). | |
//P s = 1 0 6 1 → Set VT220 keyboard emulation. | |
//P s = 2 0 0 4 → Set bracketed paste mode. | |
case 'i': | |
// Media Copy (MC). (DEC-specific) ESC [ ? i | |
//P s = 0 → Print screen (default). | |
//P s = 4 → Turn off printer controller mode. | |
//P s = 5 → Turn on printer controller mode. | |
case 'l': | |
// Reset Mode (RM). | |
//P s = 2 → Keyboard Action Mode (AM). | |
//P s = 4 → Replace Mode (IRM). | |
//P s = 1 2 → Send/receive (SRM). | |
//P s = 2 0 → Normal Linefeed (LNM). | |
// DEC Private Mode Reset (DECRST). | |
//P s = 1 → Normal Cursor Keys (DECCKM). | |
//P s = 2 → Designate VT52 mode (DECANM). | |
//P s = 3 → 80 Column Mode (DECCOLM). | |
//P s = 4 → Jump (Fast) Scroll (DECSCLM). | |
//P s = 5 → Normal Video (DECSCNM). | |
//P s = 6 → Normal Cursor Mode (DECOM). | |
//P s = 7 → No Wraparound Mode (DECAWM). | |
//P s = 8 → No Auto-repeat Keys (DECARM). | |
//P s = 9 → Don’t send Mouse X & Y on button press. | |
//P s = 1 0 → Hide toolbar (rxvt). | |
//P s = 1 2 → Stop Blinking Cursor (att610). | |
//P s = 1 8 → Don’t print form feed (DECPFF). | |
//P s = 1 9 → Limit print to scrolling region (DECPEX). | |
//P s = 2 5 → Hide Cursor (DECTCEM). | |
//P s = 3 0 → Don’t show scrollbar (rxvt). | |
//P s = 3 5 → Disable font-shifting functions (rxvt). | |
//P s = 4 0 → Disallow 80 → 132 Mode. | |
//P s = 4 1 → No more(1) fix (see curses resource). | |
//P s = 4 2 → Disable National Replacement Character sets (DECNRCM). | |
//P s = 4 4 → Turn Off Margin Bell. | |
//P s = 4 5 → No Reverse-wraparound Mode. | |
//P s = 4 6 → Stop Logging. (This is normally disabled by a compile-time option). | |
//P s = 4 7 → Use Normal Screen Buffer. | |
//P s = 6 6 → Numeric keypad (DECNKM). | |
//P s = 6 7 → Backarrow key sends delete (DECBKM). | |
//P s = 6 9 → Disable left and right margin mode (DECLRMM), VT420 and up. | |
//P s = 9 5 → Clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up. | |
//P s = 1 0 0 0 → Don’t send Mouse X & Y on button press and release. See the section Mouse Tracking. | |
//P s = 1 0 0 1 → Don’t use Hilite Mouse Tracking. | |
//P s = 1 0 0 2 → Don’t use Cell Motion Mouse Tracking. | |
//P s = 1 0 0 3 → Don’t use All Motion Mouse Tracking. | |
//P s = 1 0 0 4 → Don’t send FocusIn/FocusOut events. | |
//P s = 1 0 0 5 → Disable UTF-8 Mouse Mode. | |
//P s = 1 0 0 6 → Disable SGR Mouse Mode. | |
//P s = 1 0 0 7 → Disable Alternate Scroll Mode. | |
//P s = 1 0 1 0 → Don’t scroll to bottom on tty output (rxvt). | |
//P s = 1 0 1 1 → Don’t scroll to bottom on key press (rxvt). | |
//P s = 1 0 1 5 → Disable urxvt Mouse Mode. | |
//P s = 1 0 3 4 → Don’t interpret "meta" key. (This disables the eightBitInput resource). | |
//P s = 1 0 3 5 → Disable special modifiers for Alt and NumLock keys. (This disables the numLock resource). | |
//P s = 1 0 3 6 → Don’t send ESC when Meta modifies a key. (This disables the metaSendsEscape resource). | |
//P s = 1 0 3 7 → Send VT220 Remove from the editing-keypad Delete key. | |
//P s = 1 0 3 9 → Don’t send ESC when Alt modifies a key. (This disables the altSendsEscape resource). | |
//P s = 1 0 4 0 → Do not keep selection when not highlighted. (This disables the keepSelection resource). | |
//P s = 1 0 4 1 → Use the PRIMARY selection. (This disables the selectToClipboard resource). | |
//P s = 1 0 4 2 → Disable Urgency window manager hint when Control-G is received. (This disables the bellIsUrgent resource). | |
//P s = 1 0 4 3 → Disable raising of the window when Control-G is received. (This disables the popOnBell resource). | |
//P s = 1 0 4 7 → Use Normal Screen Buffer, clearing screen first if in the Alternate Screen. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 8 → Restore cursor as in DECRC. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 9 → Use Normal Screen Buffer and restore cursor as in DECRC. (This may be disabled by the titeInhibit resource). This combines the effects of the 1 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based applications rather than the 4 7 mode. | |
//P s = 1 0 5 0 → Reset terminfo/termcap function-key mode. | |
//P s = 1 0 5 1 → Reset Sun function-key mode. | |
//P s = 1 0 5 2 → Reset HP function-key mode. | |
//P s = 1 0 5 3 → Reset SCO function-key mode. | |
//P s = 1 0 6 0 → Reset legacy keyboard emulation (X11R6). | |
//P s = 1 0 6 1 → Reset keyboard emulation to Sun/PC style. | |
//P s = 2 0 0 4 → Reset bracketed paste mode. | |
case 'm': | |
// Character Attributes (SGR). | |
//P s = 0 → Normal (default). | |
//P s = 1 → Bold. | |
//P s = 2 → Faint, decreased intensity (ISO 6429). | |
//P s = 3 → Italicized (ISO 6429). | |
//P s = 4 → Underlined. | |
//P s = 5 → Blink (appears as Bold). | |
//P s = 7 → Inverse. | |
//P s = 8 → Invisible, i.e., hidden (VT300). | |
//P s = 9 → Crossed-out characters (ISO 6429). | |
//P s = 2 1 → Doubly-underlined (ISO 6429). | |
//P s = 2 2 → Normal (neither bold nor faint). | |
//P s = 2 3 → Not italicized (ISO 6429). | |
//P s = 2 4 → Not underlined. | |
//P s = 2 5 → Steady (not blinking). | |
//P s = 2 7 → Positive (not inverse). | |
//P s = 2 8 → Visible, i.e., not hidden (VT300). | |
//P s = 2 9 → Not crossed-out (ISO 6429). | |
//P s = 3 0 → Set foreground color to Black. | |
//P s = 3 1 → Set foreground color to Red. | |
//P s = 3 2 → Set foreground color to Green. | |
//P s = 3 3 → Set foreground color to Yellow. | |
//P s = 3 4 → Set foreground color to Blue. | |
//P s = 3 5 → Set foreground color to Magenta. | |
//P s = 3 6 → Set foreground color to Cyan. | |
//P s = 3 7 → Set foreground color to White. | |
//P s = 3 9 → Set foreground color to default (original). | |
//P s = 4 0 → Set background color to Black. | |
//P s = 4 1 → Set background color to Red. | |
//P s = 4 2 → Set background color to Green. | |
//P s = 4 3 → Set background color to Yellow. | |
//P s = 4 4 → Set background color to Blue. | |
//P s = 4 5 → Set background color to Magenta. | |
//P s = 4 6 → Set background color to Cyan. | |
//P s = 4 7 → Set background color to White. | |
//P s = 4 9 → Set background color to default (original). | |
// If 16-color support is compiled, the following apply. Assume that xterm’s resources are set so that the ISO color codes are the first 8 of a set of 16. | |
// Then the aixterm colors are the bright versions of the ISO colors: | |
//P s = 9 0 → Set foreground color to Black. | |
//P s = 9 1 → Set foreground color to Red. | |
//P s = 9 2 → Set foreground color to Green. | |
//P s = 9 3 → Set foreground color to Yellow. | |
//P s = 9 4 → Set foreground color to Blue. | |
//P s = 9 5 → Set foreground color to Magenta. | |
//P s = 9 6 → Set foreground color to Cyan. | |
//P s = 9 7 → Set foreground color to White. | |
//P s = 1 0 0 → Set background color to Black. | |
//P s = 1 0 1 → Set background color to Red. | |
//P s = 1 0 2 → Set background color to Green. | |
//P s = 1 0 3 → Set background color to Yellow. | |
//P s = 1 0 4 → Set background color to Blue. | |
//P s = 1 0 5 → Set background color to Magenta. | |
//P s = 1 0 6 → Set background color to Cyan. | |
//P s = 1 0 7 → Set background color to White. | |
// If xterm is compiled with the 16-color support disabled, it supports the following, from rxvt: | |
//P s = 1 0 0 → Set foreground and background color to default. | |
// Xterm maintains a color palette whose entries are identified by an index beginning with zero. If 88- or 256-color support is compiled, the following apply: | |
//All parameters are decimal integers. | |
//RGB values range from zero (0) to 255. | |
//ISO-8613-3 can be interpreted in more than one way; xterm allows the semicolons in this control to be replaced by colons (but after the first colon, colons must be used). | |
// These ISO-8613-3 controls are supported: | |
//P s = 3 8 ; 2 ; P r ; P g ; P b → Set foreground color to the closest match in xterm’s palette for the given RGB P r /P g /P b . | |
//P s = 3 8 ; 5 ; P s → Set foreground color to the second P s . | |
//P s = 4 8 ; 2 ; P r ; P g ; P b → Set background color to the closest match in xterm’s palette for the given RGB P r /P g /P b . | |
//P s = 4 8 ; 5 ; P s → Set background color to the second P s . | |
case 'n': | |
// Device Status Report (DSR). | |
//P s = 5 → Status Report. Result (‘‘OK’’) is | |
//CSI 0 n | |
//P s = 6 → Report Cursor Position (CPR) [row;column]. Result is | |
//CSI r ; c R | |
// Note: it is possible for this sequence to be sent by a function | |
// key. For example, with the default keyboard configuration | |
// the shifted F1 key may send (with shift-, control-, alt-modifiers) | |
//CSI 1 ; 2 R , or | |
//CSI 1 ; 5 R , or | |
//CSI 1 ; 6 R , etc. | |
case 'p': | |
case 'q': | |
// Load LEDs (DECLL). | |
//P s = 0 → Clear all LEDS (default). | |
//P s = 1 → Light Num Lock. | |
//P s = 2 → Light Caps Lock. | |
//P s = 3 → Light Scroll Lock. | |
//P s = 2 1 → Extinguish Num Lock. | |
//P s = 2 2 → Extinguish Caps Lock. | |
//P s = 2 3 → Extinguish Scroll Lock. | |
case 'r': // Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM). | |
case 's': // Save cursor position (ANSI.SYS), available only when DECLRMM is disabled. | |
case 't': // Window manipulation (from dtterm, as well as extensions). | |
case 'u': // Restore cursor position (ANSI.SYS). | |
case 'x': | |
// Request Terminal Parameters (DECREQTPARM). | |
// if P s is a "0" (default) or "1", and xterm is emulating VT100, | |
// the control sequence elicits a response of the same form whose | |
// parameters describe the terminal: | |
//P s → the given P s incremented by 2. | |
//P n = 1 ← no parity. | |
//P n = 1 ← eight bits. | |
//P n = 1 ← 2 8 transmit 38.4k baud. | |
//P n = 1 ← 2 8 receive 38.4k baud. | |
//P n = 1 ← clock multiplier. | |
//P n = 0 ← STP flags. | |
case '!': // Soft terminal reset (DECSTR). | |
// Valid Sequences Ended. | |
sequenceCompleted = true; | |
break; | |
// Unsupported Text and Keyboard Modifiers. | |
// These are Preceeding Modifiers ie after ESC [ > | |
case '>': | |
case '$': | |
case '"': | |
case '*': | |
invalidSequence = true; | |
break; | |
case '?': // -- Switch to next sequenceLevel | |
// Ie.. handle ESC[?7h, ESC[?7l, and other ? DEC Sequences. | |
// These Sequences DEC Level Sequecnes and need extra Parsing. | |
case ' ': // Need to Precheck SyncTerm Font switching ' D' Space D. | |
++sequenceLevel; | |
break; | |
default: | |
// Nothing Matched, Shouldn't get here. | |
invalidSequence = true; | |
#ifdef _DEBUG | |
std::cout << "CSI parser exception: received ESC: " | |
<< sequence << std::endl; | |
#endif | |
break; | |
} | |
} | |
/* | |
* Level 2 Parsing Catches (2) Different Sequence Styles and Comes After ESC[ = CSI. | |
* Specifically for ? preceeding sequenceing, and ' ' Space D ending Sequence | |
* For syncterm font switching. | |
* | |
* Numbers and Seperators are found in the middle of sequences as Parameters | |
* Switch Statement catch the end of a Valid Sequence. | |
* | |
* Any nonSupported sequences can have certain charactes after the CSI | |
* and These are parsed so that they are skipped and marked Invalid. | |
*/ | |
void SequenceParser::ProcessLevel2() | |
{ | |
// If the last addition to seqeunce is a space and we are now here. | |
// The only valid terminator = 'D' for Sycnterm Font Switching. | |
#ifdef _DEBUG | |
std::cout << "bad sequence check: '" << sequenceBuilder[sequenceBuilder.size()-2] << "' " << sequence << std::endl; | |
#endif | |
if (sequenceBuilder[sequenceBuilder.size()-2] == ' ' && sequence != 'D') | |
{ | |
#ifdef _DEBUG | |
std::cout << "Invalid space found in sequence!" << std::endl; | |
#endif | |
invalidSequence = true; | |
return; | |
} | |
// If we get here, only valid Sequences are ESC [ Then next Character. | |
// First Check for Parameters in Sequence | |
if (std::isdigit(sequence)) // Mark for Parameter | |
{ | |
// Contine to next sequence | |
#ifdef _DEBUG | |
std::cout << "Is a Number: " << sequence << std::endl; | |
#endif | |
return; | |
} | |
else | |
if (sequence == ';') // Mark for Multi-Parameter | |
{ | |
// Continue to Next Sequence | |
#ifdef _DEBUG | |
std::cout << "Is a Seperator: " << sequence << std::endl; | |
#endif | |
return; | |
} | |
// Catch Valid ESC Sequence Terminators. | |
switch (sequence) | |
{ | |
case 'D': | |
// SyncTerm Font Switching Sequences | |
// Syncterm Sequences have a Space before the D, | |
// If a space is found, the sequence is passed from the previous level. | |
// ESC [0;0 D | |
// First we are catching DEC Style ESC[? Parameters here. | |
case 'J': | |
// Erase in Display (ED). - DECSED has ESC[?J | |
//P s = 0 → Erase Below (default). | |
//P s = 1 → Erase Above. | |
//P s = 2 → Erase All. | |
case 'K': | |
// Erase in Line (EL). - DECSED has ESC[?K | |
//P s = 0 → Erase to Right (default). | |
//P s = 1 → Erase to Left. | |
//P s = 2 → Erase All. | |
case 'h': | |
// DEC Private Mode Set (DECSET). ESC [ ? h | |
//P s = 1 → Application Cursor Keys (DECCKM). | |
//P s = 2 → Designate USASCII for character sets G0-G3 (DECANM), and set VT100 mode. | |
//P s = 3 → 132 Column Mode (DECCOLM). | |
//P s = 4 → Smooth (Slow) Scroll (DECSCLM). | |
//P s = 5 → Reverse Video (DECSCNM). | |
//P s = 6 → Origin Mode (DECOM). | |
//P s = 7 → Wraparound Mode (DECAWM). | |
//P s = 8 → Auto-repeat Keys (DECARM). | |
//P s = 9 → Send Mouse X & Y on button press. See the section Mouse Tracking. This is the X10 xterm mouse protocol. | |
//P s = 1 0 → Show toolbar (rxvt). | |
//P s = 1 2 → Start Blinking Cursor (att610). | |
//P s = 1 8 → Print form feed (DECPFF). | |
//P s = 1 9 → Set print extent to full screen (DECPEX). | |
//P s = 2 5 → Show Cursor (DECTCEM). | |
//P s = 3 0 → Show scrollbar (rxvt). | |
//P s = 3 5 → Enable font-shifting functions (rxvt). | |
//P s = 3 8 → Enter Tektronix Mode (DECTEK). | |
//P s = 4 0 → Allow 80 → 132 Mode. | |
//P s = 4 1 → more(1) fix (see curses resource). | |
//P s = 4 2 → Enable National Replacement Character sets (DECNRCM). | |
//P s = 4 4 → Turn On Margin Bell. | |
//P s = 4 5 → Reverse-wraparound Mode. | |
//P s = 4 6 → Start Logging. This is normally disabled by a compile-time option. | |
//P s = 4 7 → Use Alternate Screen Buffer. (This may be disabled by the titeInhibit resource). | |
//P s = 6 6 → Application keypad (DECNKM). | |
//P s = 6 7 → Backarrow key sends backspace (DECBKM). | |
//P s = 6 9 → Enable left and right margin mode (DECLRMM), VT420 and up. | |
//P s = 9 5 → Do not clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up. | |
//P s = 1 0 0 0 → Send Mouse X & Y on button press and release. See the section Mouse Tracking. This is the X11 xterm mouse protocol. | |
//P s = 1 0 0 1 → Use Hilite Mouse Tracking. | |
//P s = 1 0 0 2 → Use Cell Motion Mouse Tracking. | |
//P s = 1 0 0 3 → Use All Motion Mouse Tracking. | |
//P s = 1 0 0 4 → Send FocusIn/FocusOut events. | |
//P s = 1 0 0 5 → Enable UTF-8 Mouse Mode. | |
//P s = 1 0 0 6 → Enable SGR Mouse Mode. | |
//P s = 1 0 0 7 → Enable Alternate Scroll Mode. | |
//P s = 1 0 1 0 → Scroll to bottom on tty output (rxvt). | |
//P s = 1 0 1 1 → Scroll to bottom on key press (rxvt). | |
//P s = 1 0 1 5 → Enable urxvt Mouse Mode. | |
//P s = 1 0 3 4 → Interpret "meta" key, sets eighth bit. (enables the eightBitInput resource). | |
//P s = 1 0 3 5 → Enable special modifiers for Alt and NumLock keys. (This enables the numLock resource). | |
//P s = 1 0 3 6 → Send ESC when Meta modifies a key. (This enables the metaSendsEscape resource). | |
//P s = 1 0 3 7 → Send DEL from the editing-keypad Delete key. | |
//P s = 1 0 3 9 → Send ESC when Alt modifies a key. (This enables the altSendsEscape resource). | |
//P s = 1 0 4 0 → Keep selection even if not highlighted. (This enables the keepSelection resource). | |
//P s = 1 0 4 1 → Use the CLIPBOARD selection. (This enables the selectToClipboard resource). | |
//P s = 1 0 4 2 → Enable Urgency window manager hint when Control-G is received. (This enables the bellIsUrgent resource). | |
//P s = 1 0 4 3 → Enable raising of the window when Control-G is received. (enables the popOnBell resource). | |
//P s = 1 0 4 7 → Use Alternate Screen Buffer. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 8 → Save cursor as in DECSC. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 9 → Save cursor as in DECSC and use Alternate Screen Buffer, clearing it first. (This may be disabled by the titeInhibit resource). This combines the effects of the 1 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based applications rather than the 4 7 mode. | |
//P s = 1 0 5 0 → Set terminfo/termcap function-key mode. | |
//P s = 1 0 5 1 → Set Sun function-key mode. | |
//P s = 1 0 5 2 → Set HP function-key mode. | |
//P s = 1 0 5 3 → Set SCO function-key mode. | |
//P s = 1 0 6 0 → Set legacy keyboard emulation (X11R6). | |
//P s = 1 0 6 1 → Set VT220 keyboard emulation. | |
//P s = 2 0 0 4 → Set bracketed paste mode. | |
case 'i': | |
// Media Copy (MC, DEC-specific). | |
//P s = 1 → Print line containing cursor. | |
//P s = 4 → Turn off autoprint mode. | |
//P s = 5 → Turn on autoprint mode. | |
//P s = 1 0 → Print composed display, ignores DECPEX. | |
//P s = 1 1 → Print all pages. | |
case 'l': | |
// DEC Private Mode Reset (DECRST). | |
//P s = 1 → Normal Cursor Keys (DECCKM). | |
//P s = 2 → Designate VT52 mode (DECANM). | |
//P s = 3 → 80 Column Mode (DECCOLM). | |
//P s = 4 → Jump (Fast) Scroll (DECSCLM). | |
//P s = 5 → Normal Video (DECSCNM). | |
//P s = 6 → Normal Cursor Mode (DECOM). | |
//P s = 7 → No Wraparound Mode (DECAWM). | |
//P s = 8 → No Auto-repeat Keys (DECARM). | |
//P s = 9 → Don’t send Mouse X & Y on button press. | |
//P s = 1 0 → Hide toolbar (rxvt). | |
//P s = 1 2 → Stop Blinking Cursor (att610). | |
//P s = 1 8 → Don’t print form feed (DECPFF). | |
//P s = 1 9 → Limit print to scrolling region (DECPEX). | |
//P s = 2 5 → Hide Cursor (DECTCEM). | |
//P s = 3 0 → Don’t show scrollbar (rxvt). | |
//P s = 3 5 → Disable font-shifting functions (rxvt). | |
//P s = 4 0 → Disallow 80 → 132 Mode. | |
//P s = 4 1 → No more(1) fix (see curses resource). | |
//P s = 4 2 → Disable National Replacement Character sets (DECNRCM). | |
//P s = 4 4 → Turn Off Margin Bell. | |
//P s = 4 5 → No Reverse-wraparound Mode. | |
//P s = 4 6 → Stop Logging. (This is normally disabled by a compile-time option). | |
//P s = 4 7 → Use Normal Screen Buffer. | |
//P s = 6 6 → Numeric keypad (DECNKM). | |
//P s = 6 7 → Backarrow key sends delete (DECBKM). | |
//P s = 6 9 → Disable left and right margin mode (DECLRMM), VT420 and up. | |
//P s = 9 5 → Clear screen when DECCOLM is set/reset (DECNCSM), VT510 and up. | |
//P s = 1 0 0 0 → Don’t send Mouse X & Y on button press and release. See the section Mouse Tracking. | |
//P s = 1 0 0 1 → Don’t use Hilite Mouse Tracking. | |
//P s = 1 0 0 2 → Don’t use Cell Motion Mouse Tracking. | |
//P s = 1 0 0 3 → Don’t use All Motion Mouse Tracking. | |
//P s = 1 0 0 4 → Don’t send FocusIn/FocusOut events. | |
//P s = 1 0 0 5 → Disable UTF-8 Mouse Mode. | |
//P s = 1 0 0 6 → Disable SGR Mouse Mode. | |
//P s = 1 0 0 7 → Disable Alternate Scroll Mode. | |
//P s = 1 0 1 0 → Don’t scroll to bottom on tty output (rxvt). | |
//P s = 1 0 1 1 → Don’t scroll to bottom on key press (rxvt). | |
//P s = 1 0 1 5 → Disable urxvt Mouse Mode. | |
//P s = 1 0 3 4 → Don’t interpret "meta" key. (This disables the eightBitInput resource). | |
//P s = 1 0 3 5 → Disable special modifiers for Alt and NumLock keys. (This disables the numLock resource). | |
//P s = 1 0 3 6 → Don’t send ESC when Meta modifies a key. (This disables the metaSendsEscape resource). | |
//P s = 1 0 3 7 → Send VT220 Remove from the editing-keypad Delete key. | |
//P s = 1 0 3 9 → Don’t send ESC when Alt modifies a key. (This disables the altSendsEscape resource). | |
//P s = 1 0 4 0 → Do not keep selection when not highlighted. (This disables the keepSelection resource). | |
//P s = 1 0 4 1 → Use the PRIMARY selection. (This disables the selectToClipboard resource). | |
//P s = 1 0 4 2 → Disable Urgency window manager hint when Control-G is received. (This disables the bellIsUrgent resource). | |
//P s = 1 0 4 3 → Disable raising of the window when Control-G is received. (This disables the popOnBell resource). | |
//P s = 1 0 4 7 → Use Normal Screen Buffer, clearing screen first if in the Alternate Screen. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 8 → Restore cursor as in DECRC. (This may be disabled by the titeInhibit resource). | |
//P s = 1 0 4 9 → Use Normal Screen Buffer and restore cursor as in DECRC. (This may be disabled by the titeInhibit resource). This combines the effects of the 1 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based applications rather than the 4 7 mode. | |
//P s = 1 0 5 0 → Reset terminfo/termcap function-key mode. | |
//P s = 1 0 5 1 → Reset Sun function-key mode. | |
//P s = 1 0 5 2 → Reset HP function-key mode. | |
//P s = 1 0 5 3 → Reset SCO function-key mode. | |
//P s = 1 0 6 0 → Reset legacy keyboard emulation (X11R6). | |
//P s = 1 0 6 1 → Reset keyboard emulation to Sun/PC style. | |
//P s = 2 0 0 4 → Reset bracketed paste mode. | |
case 'n': | |
// Device Status Report (DSR, DEC-specific). | |
//P s = 6 → Report Cursor Position (DECXCPR) [row;column] as CSI ? r ; c R (assumes the default page, i.e., "1"). | |
//P s = 1 5 → Report Printer status as CSI ? 1 0 n (ready). or CSI ? 1 1 n (not ready). | |
//P s = 2 5 → Report UDK status as CSI ? 2 0 n (unlocked) or CSI ? 2 1 n (locked). | |
//P s = 2 6 → Report Keyboard status as | |
//CSI ? 2 7 ; 1 ; 0 ; 0 n (North American). | |
//The last two parameters apply to VT400 & up, and denote keyboard ready and LK01 respectively. | |
//P s = 5 3 → Report Locator status as CSI ? 5 3 n Locator available, if compiled-in, or CSI ? 5 0 n No Locator, if not. | |
//P s = 5 5 → Report Locator status as CSI ? 5 3 n Locator available, if compiled-in, or CSI ? 5 0 n No Locator, if not. | |
//P s = 5 6 → Report Locator type as CSI ? 5 7 ; 1 n Mouse, if compiled-in, or CSI ? 5 7 ; 0 n Cannot identify, if not. | |
//P s = 6 2 → Report macro space (DECMSR) as CSI P n \* { | |
//P s = 6 3 → Report memory checksum (DECCKSR) as DCS P t ! x x x x ST | |
//P t is the request id (from an optional parameter to the request). | |
//The x’s are hexadecimal digits 0-9 and A-F. | |
//P s = 7 5 → Report data integrity as CSI ? 7 0 n (ready, no errors) | |
//P s = 8 5 → Report multi-session configuration as CSI ? 8 3 n (not configured for multiple-session operation). | |
case 'p': | |
case 'q': | |
// Load LEDs (DECLL). | |
//P s = 0 → Clear all LEDS (default). | |
//P s = 1 → Light Num Lock. | |
//P s = 2 → Light Caps Lock. | |
//P s = 3 → Light Scroll Lock. | |
//P s = 2 1 → Extinguish Num Lock. | |
//P s = 2 2 → Extinguish Caps Lock. | |
//P s = 2 3 → Extinguish Scroll Lock. | |
case 'r': // Restore DEC Private Mode Values. The value of P s previously saved is restored. P s values are the same as for DECSET. | |
case 's': // Save DEC Private Mode Values. P s values are the same as for DECSET. | |
case '!': // Soft terminal reset (DECSTR). | |
// Valid Sequences Ended. | |
sequenceCompleted = true; | |
break; | |
// Unsupported Text and Keyboard Modifiers. | |
// These are Preceeding Modifiers ie after ESC [ > | |
case '>': | |
case '$': | |
case '"': | |
case '*': | |
case ' ': | |
invalidSequence = true; | |
break; | |
default: | |
// Nothing Matched, Shouldn't get here. | |
invalidSequence = true; | |
#ifdef _DEBUG | |
std::cout << "CSI parser exception: received ESC: " | |
<< sequence << std::endl; | |
#endif | |
break; | |
} | |
} | |
/* | |
* Validate Complete ESC Control Sequences | |
* Break up the parameters into a Vector | |
* For easier pre-parsing of Screen Display. | |
*/ | |
void SequenceParser::ValidateSequence() | |
{ | |
#ifdef _DEBUG | |
std::cout << "Validate Sequence: " << sequenceBuilder << std::endl; | |
#endif | |
int sequenceTerminator = 0; | |
// Check and clear vector for fresh sequence | |
// We only Validate on complete sequences, so we can clear here | |
// to make sure each run. | |
if (params.size() > 0) | |
std::vector<int>().swap(params); | |
#ifdef _DEBUG | |
std::cout << "Params Size(): " << params.size() << std::endl; | |
#endif | |
// If we get there, we have full CSI with possiable ; ; seperators. | |
try | |
{ | |
sequenceBuilder.erase(0,2); // Remove ESC [ | |
sequenceTerminator = // Get Terminator | |
sequenceBuilder[sequenceBuilder.size()-1]; | |
// First Parameter is always the SequenceTerminator. | |
params.push_back(sequenceTerminator); | |
// Remove Sequence Terminator from string to text for parameters. | |
sequenceBuilder.erase(sequenceBuilder.size()-1,1); | |
} | |
catch (std::exception e) | |
{ | |
std::cout << "Exception removing ESC and Terminator Sequences: " | |
<< e.what() << std::endl; | |
} | |
// Split String by ';' character to seperate parameters if it exists. | |
if (sequenceBuilder.size() == 0) | |
{ | |
// We have no parameters, just terminator for single sequence. | |
#ifdef _DEBUG | |
std::cout << "No params Vector: " << std::endl; | |
int ii = 1; | |
std::vector<int>::iterator it; | |
for(it = params.begin(); it != params.end(); ++it) | |
{ | |
std::cout << ii++ << " " << *it << " " << static_cast<char>(*it) << std::endl; | |
} | |
#endif | |
return; | |
} | |
// If we have a parameter seqerator, then tokenize the parameters. | |
std::string::size_type result = sequenceBuilder.find(";",0); | |
if (result != std::string::npos) | |
{ | |
std::istringstream inStream(sequenceBuilder); | |
std::istringstream tokenStream; | |
std::string token; | |
// 0;33;47 Splits 0 33 47 | |
// ignores spaces. | |
#ifdef _DEBUG | |
int ii = 1; | |
std::cout << "result = TRUE, found ; seperator." << std::endl; | |
#endif | |
while(std::getline(inStream, token, ';')) | |
{ | |
tokenStream.clear(); | |
if (token.size() == 0) | |
{ | |
#ifdef _DEBUG | |
std::cout << "Empty " << std::flush; | |
#endif | |
token = "-1"; // Empty fields are set to -1 for implied parms. | |
} | |
#ifdef _DEBUG | |
std::cout << ii++ << " " << "Token: " << token << std::endl; | |
#endif | |
tokenStream.str(token); // Token to Stream | |
if ((tokenStream >> parameter).fail()) // String to Int | |
{ | |
// Skip this character. | |
std::cout << "Exception String to Int Parameter Failure." | |
<< std::endl; | |
continue; | |
} | |
params.push_back(parameter); // Add to Parameteres Vector. | |
} | |
} | |
else | |
{ | |
// First check for ? DEC Sequence Starter | |
if (sequenceBuilder[0] == '?') | |
{ | |
#ifdef _DEBUG | |
std::cout << "removing ? from sequence" << std::endl; | |
#endif | |
try | |
{ | |
params.push_back('?'); // Add to Parameteres Vector. | |
sequenceBuilder.erase(0,1); // Remove ? | |
} | |
catch (std::exception e) | |
{ | |
std::cout << "Exception removing ? sequence starter: " | |
<< e.what() << std::endl; | |
} | |
} | |
// No seperator, translate the 1-3 digit code that should be present. | |
std::istringstream tokenStream; | |
tokenStream.str(sequenceBuilder); // String to Stream | |
if ((tokenStream >> parameter).fail()) // String to Int | |
{ | |
// Skip this character. | |
std::cout << "Exception String to Int Parameter Failure." | |
<< std::endl; | |
} | |
else | |
params.push_back(parameter); // Add to Parameteres Vector. | |
} | |
#ifdef _DEBUG | |
// Testing output of vector. | |
std::cout << "Vector: " << std::endl; | |
int ii = 1; | |
std::vector<int>::iterator it; | |
for(it = params.begin(); it != params.end(); ++it) | |
{ | |
std::cout << ii++ << " " << *it << " " << static_cast<char>(*it) << std::endl; | |
} | |
#endif | |
} | |
/* | |
* Takes String input and parses for ESC Control Sequences | |
* State machine stays actives waiting for complete control sequences | |
* before pushing any actions forwards. Normal Text data is passed through. | |
*/ | |
void SequenceParser::ProcessSequence(std::string inputString) | |
{ | |
//Parse entire string and remove any double ESC Sequences. | |
std::string::size_type result = 0; | |
while (result != std::string::npos) | |
{ | |
result = inputString.find("\x1b\x1b"); | |
if (result != std::string::npos) | |
{ | |
#ifdef _DEBUG | |
std::cout << "Found Double ESC!" << std::endl; | |
#endif | |
try | |
{ | |
inputString.replace(result,1,"^"); | |
} | |
catch (std::exception e) | |
{ | |
std::cout << "Exception replacing double ESC characters: " | |
<< e.what() << std::endl; | |
sequenceState = SEQ_ERROR; // Reset The State | |
} | |
} | |
} | |
// Now loop enire string and find valid escape sequences. | |
for (std::string::size_type i = 0; i < inputString.size(); i++) | |
{ | |
#ifdef _DEBUG | |
std::cout << "sequenceState: " << sequenceState << std::endl; | |
#endif | |
// Get next Input Sequence | |
sequence = inputString[i]; | |
// Check for Start of Sequence, if we hit a sequence we then need | |
// To send all Valid Output that Proceeds this sequence so everything | |
// is FIFO with regards to how incoming data is handeled. | |
if (sequence == '\x1b') | |
{ | |
sequenceState = SEQ_START; | |
} | |
// Pre-Handle the Parser State | |
switch(sequenceState) | |
{ | |
// Normal Text Data, Append to Buffer | |
case SEQ_NORMAL: | |
validOutputData += sequence; | |
break; | |
// Start of Sequence, Push ValidOutputData Buffer Through | |
// Then switch to Processing State, So we have FIFO Data | |
// Parsing. | |
case SEQ_START: | |
// TheAnsiParser::Instance()->textinput(validOutputData); | |
validOutputData.erase(); | |
sequenceState = SEQ_PROCESSING; | |
sequenceBuilder += sequence; | |
break; | |
case SEQ_PROCESSING: | |
// Were in the middle of processing a control sequence | |
// Keep is going till we get DONE! | |
sequenceBuilder += sequence; | |
break; | |
case SEQ_ERROR: | |
// Validing the Sequence Bombed, Clear the vector and continue. | |
std::vector<int>().swap(params); // Clear for next run. | |
sequenceBuilder.erase(); // Clear Any Prebuilt. | |
sequenceState = SEQ_NORMAL; | |
continue; | |
} | |
if (sequence == '\x1b' && !sequenceCompleted) | |
{ | |
// Error Checking, If were in the middle of an incomplete sequence | |
// Then we shouldn't get an ESC before we complete the sequence! | |
if (foundSequence) | |
{ | |
#ifdef _DEBUG | |
std::cout << "Invalid Sequence, ESC in current sequence" | |
<< std::endl; | |
#endif | |
// We now determine the preceeding sequence is invalid | |
// And remove the ESC, then proceed with the current sequence | |
try | |
{ | |
// Change to SequenceBuilder, don't touch input string | |
// If it's broken into multiple input, then this is no | |
// longer viable. | |
//inputString.replace(escapePosition,1,"^"); | |
sequenceBuilder.replace(0,1,"^"); // ESC to ^ | |
} | |
catch (std::exception e) | |
{ | |
std::cout << "Exception replace escapePosition: " | |
<< e.what() << std::endl; | |
sequenceState = SEQ_ERROR; // Reset The State | |
} | |
} | |
#ifdef _DEBUG | |
std::cout << "ESC starting new sequence parsing" << std::endl; | |
#endif | |
escapePosition = i; | |
foundSequence = true; | |
continue; | |
} | |
// Each Level is the next character after the ESC | |
// Check the first few levels to make sure we have a valid CSI | |
if (foundSequence && !invalidSequence) | |
{ | |
switch(sequenceLevel) | |
{ | |
case 0: // Process first char after ESC '[' | |
#ifdef _DEBUG | |
std::cout << "sequenceLevel: " << sequenceLevel << " : " | |
<< sequence << std::endl; | |
#endif | |
ProcessLevel0(); | |
// Move to next Level if valid. | |
if (!invalidSequence) | |
++sequenceLevel; | |
break; | |
case 1: // Process second char after ESC [ 'c' | |
#ifdef _DEBUG | |
std::cout << "sequenceLevel: " << sequenceLevel << " : " | |
<< sequence << std::endl; | |
#endif | |
ProcessLevel1(); | |
break; | |
case 2: // Process 2nd char after ESC [ '?' DEC Sequences | |
#ifdef _DEBUG | |
std::cout << "sequenceLevel: " << sequenceLevel << " : " | |
<< sequence << std::endl; | |
#endif | |
ProcessLevel2(); | |
break; | |
} | |
} | |
// Handle Completed Control Sequences | |
if (sequenceCompleted) | |
{ | |
#ifdef _DEBUG | |
std::cout << "SequenceCompleted!" << std::endl; | |
#endif | |
// Copy just this sequenec into string for validation | |
try | |
{ | |
//escapeSequence = | |
// inputString.substr(escapePosition,(i+1)-escapePosition); | |
// Break up the sequence into seperate parameters for | |
// The Screen Parser. | |
ValidateSequence(); | |
sequenceState = SEQ_DONE; | |
} | |
catch (std::exception e) | |
{ | |
std::cout << "Exception substring on escapeSequence: " | |
<< e.what() << std::endl; | |
sequenceState = SEQ_ERROR; | |
} | |
// If the sequence is completed, The Parse the parameters and | |
// Setup for ANSI Parser and Drawing to Screen. | |
sequenceCompleted = false; | |
foundSequence = false; | |
invalidSequence = false; | |
sequenceLevel = 0; | |
} | |
// Invalid Sequences, Replace ESC with ^ characters for display | |
// Then move on. | |
if (invalidSequence) | |
{ | |
#ifdef _DEBUG | |
std::cout << " *** SequenceInvalid!" << std::endl; | |
#endif | |
// Handle Invalid Sequences by removeing the ESC character, then | |
// Continue on to the next sequence. | |
try | |
{ | |
//inputString.replace(escapePosition,1,"^"); | |
sequenceBuilder.replace(0,1,"^"); | |
} | |
catch (std::exception e) | |
{ | |
std::cout << "Exception replace escapePosition: " | |
<< e.what() << std::endl; | |
sequenceState = SEQ_ERROR; // Reset The State | |
} | |
foundSequence = false; | |
invalidSequence = false; | |
sequenceLevel = 0; | |
// First grab the entire sequence parsed so far, from ESC position | |
// Place it into validOutputData to display on the screen, | |
// We don't want To reset the loop becasue it will incriment, | |
// so we grab all characters parsed so far. | |
try | |
{ | |
validOutputData += sequenceBuilder; | |
sequenceBuilder.erase(); | |
//inputString.substr(escapePosition, (i+1) - escapePosition); | |
} | |
catch (std::exception e) | |
{ | |
std::cout << "Exception substring on ESC Position: " | |
<< e.what() << std::endl; | |
} | |
// Reset the State | |
sequenceState = SEQ_ERROR; | |
} | |
// Post-Handle the Parser State | |
switch(sequenceState) | |
{ | |
case SEQ_PROCESSING: | |
// Were in the middle of processing a control sequence | |
// Keep is going till we get DONE! | |
break; | |
case SEQ_DONE: | |
// We hit an entire sequence, pass the vector | |
// TheAnsiParser::Instance()->sequenceinput(params); | |
std::vector<int>().swap(params); // Clear for next run. | |
sequenceState = SEQ_NORMAL; // Reset The State | |
sequenceBuilder.erase(); | |
break; | |
case SEQ_ERROR: | |
// Validing the Sequence Bombed, Clear the vector and continue. | |
std::vector<int>().swap(params); // Clear for next run. | |
sequenceState = SEQ_NORMAL; // Reset The State | |
sequenceBuilder.erase(); | |
break; | |
} | |
} | |
#ifdef _DEBUG | |
// Test Display Valid Output Data | |
std::cout << std::endl | |
<< "===========================================================" | |
<< std::endl; | |
std::cout << std::endl << "valid data: " << validOutputData | |
<< std::endl << std::endl; | |
#endif | |
// Catch any echo'ed input that passed through with no sequences | |
if (sequenceState == SEQ_NORMAL && validOutputData.size() > 0) | |
{ | |
//TheAnsiParser::Instance()->TextInput(validOutputData); | |
validOutputData.erase(); | |
} | |
// Display final screen. | |
//TheTerm::Instance()->RenderScreen(); | |
//TheTerm::Instance()->DrawTextureScreen(); | |
} | |
// Test Cases for Class. | |
int main(int argc, char **argv) | |
{ | |
// ESC Sequence | |
std::string inputString; | |
// Test a split ESC sequence in seperate strings | |
// Valid Sequence | |
inputString = "\x1b[1;34;2"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Part ][ | |
inputString = "55;255;255m"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Invalid & Valid Sequence Sequence | |
inputString = "\x1b\x1b[A"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Valid Text Data | |
inputString = " ***Testing*** "; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Invalid Sequence | |
inputString = "\x1b[0;0 M"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Valid Sequence | |
inputString = "\x1b[0;0 D"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Valid Sequence | |
inputString = "\x1b[A"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Valid Sequence | |
inputString = "\x1b[422A"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Valid Sequence | |
inputString = "\x1b[0;48;255;255;255m"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Invalid Spaces in the middle | |
// Space only valid if Ending sequence = 'D' | |
inputString = "\x1b[0; 48;255 ;255;255m"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Valid DESC Sequence with Pre-Control Characters. | |
inputString = "\x1b[?7h"; | |
TheSequenceParser::Instance()->ProcessSequence(inputString); | |
// Clear and Release Instance. | |
TheSequenceParser::ReleaseInstance(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment