X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Fgui_terminal_src%2Fvt100.c;h=6a2321ea7e91f88168ef81e50e333434229f7297;hb=98bd9c0c8985c50c42231c116a4e18fedd47761e;hp=4af6403da3f52c4944684cd1ba056ecc08631b6d;hpb=719c74c0763d27de41101ded34836cea66dc04aa;p=tpg%2Facess2.git diff --git a/Usermode/Applications/gui_terminal_src/vt100.c b/Usermode/Applications/gui_terminal_src/vt100.c index 4af6403d..6a2321ea 100644 --- a/Usermode/Applications/gui_terminal_src/vt100.c +++ b/Usermode/Applications/gui_terminal_src/vt100.c @@ -15,6 +15,14 @@ # include // _SysDebug # include # include +# include // malloc/free + +# define ASSERTC(a, r, b) assert(a r b) + +static inline int MIN(int a, int b) +{ + return a < b ? a : b; +} #endif enum eExcapeMode { @@ -30,10 +38,14 @@ enum eStringType { #define FLAG_BOLD 0x01 #define FLAG_REVERSE 0x02 +#define MAX_VT100_ESCAPE_LEN 32 typedef struct { uint32_t Flags; int CurFG, CurBG; - + + char cache[MAX_VT100_ESCAPE_LEN]; + int cache_len; + enum eExcapeMode Mode; enum eStringType StringType; @@ -49,18 +61,13 @@ const uint32_t caVT100Colours[] = { }; int _locate_eos(size_t Len, const char *Buf); - int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buf); int Term_HandleVT100_Short(tTerminal *Term, int Len, const char *Buf); - -static inline int min(int a, int b) -{ - return a < b ? a : b; -} + int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buf); + int Term_HandleVT100_OSC(tTerminal *Term, int Len, const char *Buf); int _locate_eos(size_t Len, const char *Buf) { - size_t ret = 0; - while( ret < Len ) + for( size_t ret = 0; ret < Len; ret ++ ) { if( Buf[ret] == '\007' ) return ret; @@ -72,11 +79,16 @@ int _locate_eos(size_t Len, const char *Buf) return -1; } +/** + * \brief Detect and handle VT100/ANSI/xterm escape sequences + * \param Term Terminal handle (opaque) + * \param Len Number of avaliable bytes + * \param Buf Input buffer (\a Len bytes long) + * \return -ve : Number of bytes that should be sent to screen + * \return +ve/0 : Number of bytes consumed by this function + */ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) { - #define MAX_VT100_ESCAPE_LEN 16 - static char inc_buf[MAX_VT100_ESCAPE_LEN]; - static int inc_len = 0; tVT100State *st = Display_GetTermState(Term); if( st == NULL ) { @@ -88,20 +100,23 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) if( st->Mode == MODE_IGNORE ) { st->Mode = MODE_NORMAL; // Used for multi-byte EOS + _SysDebug("Ignore 1 '%c'", *Buf); return 1; } - if( st->Mode == MODE_STRING ) + else if( st->Mode == MODE_STRING ) { // We're in a string mode int pos = _locate_eos(Len, Buf); size_t bytes = (pos >= 0 ? pos : Len); char *tmp = realloc(st->StringCache, st->StringLen + bytes+1); if(!tmp) return bytes; + st->StringCache = tmp; memcpy(tmp+st->StringLen, Buf, bytes); tmp[st->StringLen+bytes] = 0; + st->StringLen += bytes; _SysDebug("pos=%i", pos); - _SysDebug("'%.*s'", bytes, Buf); + _SysDebug("Buf[+%zi] = '%.*s'", bytes, bytes, Buf); // Only apply when we hit EOS at the start if( pos != 0 ) return bytes; @@ -125,52 +140,66 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) st->Mode = MODE_NORMAL; return 1; } + else { + // fall through + } - if( inc_len > 0 || *Buf == '\x1b' ) + if( st->cache_len > 0 || *Buf == '\x1b' ) { // Handle VT100 (like) escape sequence - int new_bytes = min(MAX_VT100_ESCAPE_LEN - inc_len, Len); + int new_bytes = MIN(MAX_VT100_ESCAPE_LEN - st->cache_len, Len); int ret = 0; - int old_inc_len = inc_len; - memcpy(inc_buf + inc_len, Buf, new_bytes); + int old_inc_len = st->cache_len; + + memcpy(st->cache + st->cache_len, Buf, new_bytes); if( new_bytes == 0 ) { _SysDebug("Term_HandleVT100: Hit max? (Len=%i) Flushing cache", Len); - inc_len = 0; + st->cache_len = 0; return 0; } - inc_len += new_bytes; - //_SysDebug("inc_buf = %i '%.*s'", inc_len, inc_len, inc_buf); + st->cache_len += new_bytes; + assert(st->cache_len > old_inc_len); - if( inc_len <= 1 ) + if( st->cache_len <= 1 ) return 1; // Skip 1 character (the '\x1b') - ret = Term_HandleVT100_Short(Term, inc_len, inc_buf); + ret = Term_HandleVT100_Short(Term, st->cache_len, st->cache); if( ret != 0 ) { - inc_len = 0; - assert(ret > old_inc_len); + // Check that we actually used the new data (as should have happened) + if( ret <= old_inc_len ) { + _SysDebug("Term_HandleVT100: ret(%i) <= old_inc_len(%i), inc_len=%i, '%*C'", + ret, old_inc_len, st->cache_len, st->cache_len, st->cache); + ASSERTC(ret, >, old_inc_len); + } + st->cache_len = 0; //_SysDebug("%i bytes of escape code '%.*s' (return %i)", // ret, ret, inc_buf, ret-old_inc_len); ret -= old_inc_len; // counter cached bytes } - else + else { ret = new_bytes; + _SysDebug("Term_HandleVT100: Caching %i bytes '%*C'", ret, ret, st->cache); + } return ret; } switch( *Buf ) { - // TODO: Need to handle \t and ^A-Z + case '\a': + // Alarm, aka bell + //Display_SoundBell(Term); + break; case '\b': - Display_MoveCursor(Term, 0, -1); - Display_AddText(Term, 1, " "); + // backspace is aprarently just supposed to cursor left (if possible) Display_MoveCursor(Term, 0, -1); return 1; case '\t': // TODO: tab (get current cursor pos, space until multiple of 8) _SysDebug("TODO: VT100 Support \\t tab"); + Display_AddText(Term, 1, "\t"); // pass the buck for now return 1; case '\n': // TODO: Support disabling CR after NL @@ -208,9 +237,13 @@ int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf) return -ret; } +/** + * \brief Handle an escape code beginning with '\x1b' + * \return 0 : Insufficient data in buffer, wait for more + * \return +ve : Number of bytes in escape sequence + */ int Term_HandleVT100_Short(tTerminal *Term, int Len, const char *Buf) { - tVT100State *st = Display_GetTermState(Term); int tmp; switch(Buf[1]) { @@ -221,10 +254,26 @@ int Term_HandleVT100_Short(tTerminal *Term, int Len, const char *Buf) return 0; return tmp + 2; case ']': - st->Mode = MODE_STRING; - st->StringType = STRING_IGNORE; - _SysDebug("TODO: \\e] Support title changes"); - return 2; + tmp = Term_HandleVT100_OSC(Term, Len-2, Buf+2); + assert(tmp >= 0); + if( tmp == 0 ) + return 0; + return tmp + 2; + + case '#': + if( Len == 2 ) + return 0; + switch(Buf[2]) + { + case 8: + _SysDebug("TODO \\e#%c DECALN - Fill screen with 'E'", Buf[2]); + break; + default: + _SysDebug("Unknown \\e#%c", Buf[2]); + break; + } + return 3; + case '=': _SysDebug("TODO: \\e= Application Keypad"); return 2; @@ -251,22 +300,38 @@ int Term_HandleVT100_Short(tTerminal *Term, int Len, const char *Buf) break; } return 3; - // xterm C1 \eD and \eM are 'Index' and 'Reverse Index' - // - Aparently scroll? - //case 'D': - // Display_ScrollDown(Term, 1); - // ret = 2; - // break; - //case 'M': - // Display_ScrollDown(Term, -1); - // ret = 2; - // break; + case '7': + // Save cursor + Display_SaveCursor(Term); + return 2; + case '8': + // Restore cursor + Display_RestoreCursor(Term); + return 2; + case 'D': + // Cursor down, if at bottom scroll + Display_MoveCursor(Term, 1, 0); + // TODO: Scroll if at bottom (impl in _MoveCursor) + return 2; + case 'E': + Display_MoveCursor(Term, 1, INT_MIN); + // TODO: Scroll if at bottom (impl in _MoveCursor) + return 2; + case 'M': + // Cursor up, scroll if at top + Display_MoveCursor(Term, -1, 0); + return 2; default: _SysDebug("Unknown VT100 \\e%c", Buf[1]); return 2; } } +/** + * \brief Handle CSI escape sequences '\x1b[' + * \return 0 : insufficient data + * \return +ve : Number of bytes consumed + */ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) { tVT100State *st = Display_GetTermState(Term); @@ -278,13 +343,16 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) // Get Arguments if(j == Len) return 0; c = Buffer[j++]; - if(c == '?') { + if(c == '?') + { bQuestionMark = 1; if(j == Len) return 0; c = Buffer[j++]; } - if( '0' <= c && c <= '9' ) + if( ('0' <= c && c <= '9') || c == ';' ) { + if(c == ';') + argc ++; do { if(c == ';') { if(j == Len) return 0; @@ -322,8 +390,25 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) case 1: // Aplication cursor keys _SysDebug("TODO: \\e[?1%c Application cursor keys", c); break; + case 3: // 132 Column mode + _SysDebug("TODO: \\e[?3%c 132 Column mode", c); + break; + case 4: // Smooth (Slow) Scroll + _SysDebug("TODO: \\e[?4%c Smooth (Slow) Scroll", c); + break; + case 5: // Reverse Video + _SysDebug("TODO: \\e[?5%c Reverse Video", c); + break; + case 6: // Origin Mode + _SysDebug("TODO: \\e[?6%c Origin Mode", c); + break; + case 12: + //_SysDebug("TODO: \\e[?25%c Start/Stop blinking cursor", c); + //Display_SolidCursor(Term, !set); + break; case 25: // Hide cursor - _SysDebug("TODO: \\e[?25%c Show/Hide cursor", c); + //_SysDebug("TODO: \\e[?25%c Show/Hide cursor", c); + //Display_ShowCursor(Term, set); break; case 1047: // Alternate buffer Display_ShowAltBuffer(Term, set); @@ -351,22 +436,27 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) switch( c ) { case 'A': - Display_MoveCursor(Term, -(argc >= 1 ? args[0] : 1), 0); + Display_MoveCursor(Term, -(args[0] != 0 ? args[0] : 1), 0); break; case 'B': - Display_MoveCursor(Term, (argc >= 1 ? args[0] : 1), 0); + Display_MoveCursor(Term, (args[0] != 0 ? args[0] : 1), 0); break; case 'C': - Display_MoveCursor(Term, 0, (argc >= 1 ? args[0] : 1)); + Display_MoveCursor(Term, 0, (args[0] != 0 ? args[0] : 1)); break; case 'D': - Display_MoveCursor(Term, 0, -(argc >= 1 ? args[0] : 1)); + Display_MoveCursor(Term, 0, -(args[0] != 0 ? args[0] : 1)); break; case 'H': - if( argc != 2 ) { + if( argc == 0 ) { + Display_SetCursor(Term, 0, 0); } - else { - Display_SetCursor(Term, args[0], args[1]); + else if( argc == 1 ) { + Display_SetCursor(Term, args[0]-1, 0); + } + else if( argc == 2 ) { + // Adjust 1-based cursor position to 0-based + Display_SetCursor(Term, args[0]-1, args[1]-1); } break; case 'J': // Clear lines @@ -402,18 +492,87 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) _SysDebug("Unknown VT100 %i K", args[0]); break; } - case 'S': // Scroll up n=1 + break; + case 'S': // Scroll text up n=1 (expose bottom) Display_ScrollDown(Term, -(argc >= 1 ? args[0] : 1)); break; - case 'T': // Scroll down n=1 + case 'T': // Scroll text down n=1 (expose top) Display_ScrollDown(Term, (argc >= 1 ? args[0] : 1)); break; + case 'c': // Send Device Attributes + switch(args[0]) + { + case 0: // Request attributes from terminal + // "VT100 with Advanced Video Option" (same as screen returns) + Display_SendInput(Term, "\x1b[?1;2c"); + break; + default: + _SysDebug("TODO: Request device attributes \\e[%ic", args[0]); + break; + } + break; + case 'f': + if( argc != 2 ) { + Display_SetCursor(Term, 0, 0); + } + else { + // Adjust 1-based cursor position to 0-based + Display_SetCursor(Term, args[0]-1, args[1]-1); + } + break; + case 'h': + case 'l': + for( int i = 0; i < argc; i ++ ) + { + switch(args[i]) + { + default: + _SysDebug("Unknown VT100 mode \e[%i%c", + args[i], c); + break; + } + } + break; case 'm': if( argc == 0 ) { // Reset Display_ResetAttributes(Term); } + else if( args[0] == 48 ) + { + // ISO-8613-3 Background + if( args[1] == 2 ) { + uint32_t col = 0; + col |= (uint32_t)args[2] << 16; + col |= (uint32_t)args[3] << 8; + col |= (uint32_t)args[4] << 0; + Display_SetBackground(Term, col); + } + else if( args[1] == 5 ) { + _SysDebug("TODO: Support xterm palette BG %i", args[2]); + } + else { + _SysDebug("VT100 Unknown mode set \e[48;%im", args[1]); + } + } + else if( args[0] == 38 ) + { + // ISO-8613-3 Foreground + if( args[1] == 2 ) { + uint32_t col = 0; + col |= (uint32_t)args[2] << 16; + col |= (uint32_t)args[3] << 8; + col |= (uint32_t)args[4] << 0; + Display_SetForeground(Term, col); + } + else if( args[1] == 5 ) { + _SysDebug("TODO: Support xterm palette FG %i", args[2]); + } + else { + _SysDebug("VT100 Unknown mode set \e[38;%im", args[1]); + } + } else { for( int i = 0; i < argc; i ++ ) @@ -429,7 +588,19 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) Display_SetForeground( Term, caVT100Colours[st->CurFG + 8] ); break; case 2: - _SysDebug("TODO: VT100 \\e[1m - Reverse"); + _SysDebug("TODO: \\e[2m - Reverse"); + break; + case 4: + _SysDebug("TODO: \\e[4m - Underscore"); + break; + //case 5: + // _SysDebug("TODO: \\e[5m - Blink/bold"); + // break; + case 7: + _SysDebug("TODO: \\e[7m - Reverse"); + break; + case 24: // Not underlined + case 27: // Not inverse break; case 30 ... 37: st->CurFG = args[i]-30; @@ -446,16 +617,27 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) st->CurBG = 0; Display_SetBackground( Term, caVT100Colours[ st->CurBG ] ); break; + case 90 ... 97: + st->CurFG = args[i]-90 + 8; + Display_SetForeground( Term, caVT100Colours[ st->CurBG ] ); + break;; + case 100 ... 107: + st->CurBG = args[i]-100 + 8; + Display_SetBackground( Term, caVT100Colours[ st->CurBG ] ); + break;; default: - _SysDebug("TODO: VT100 \\e[%im", args[i]); + _SysDebug("Unknown mode set \\e[%im", args[i]); break; } } } break; + // Device Status Report + case 'n': + break; // Set scrolling region case 'r': - Display_SetScrollArea(Term, args[0], (args[1] - args[0])); + Display_SetScrollArea(Term, args[0]-1, (args[1] - args[0])+1); break; case 's': @@ -471,3 +653,61 @@ int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer) } return j; } + +int Term_HandleVT100_OSC(tTerminal *Term, int Len, const char *Buf) +{ + tVT100State *st = Display_GetTermState(Term); + + int ofs = 0; + // OSC Ps ; Pt [ST/BEL] + if(Len < 2) return 0; // Need moar + + int Ps = 0; + while( ofs < Len && isdigit(Buf[ofs]) ) { + Ps = Ps * 10 + (Buf[ofs] - '0'); + ofs ++; + } + + if( ofs == Len ) return 0; + if( Buf[ofs] != ';' ) { + // Error + st->Mode = MODE_STRING; + st->StringType = STRING_IGNORE; + return ofs; + } + ofs ++; + + switch(Ps) + { + case 0: // Icon Name + Window Title + case 1: // Icon Name + case 2: // Window Title + st->Mode = MODE_STRING; + st->StringType = STRING_TITLE; + break; + case 3: // Set X Property + _SysDebug("TODO: \\e]3; Support X properties"); + st->Mode = MODE_STRING; + st->StringType = STRING_IGNORE; + break; + case 4: // Change colour number + case 5: // Change special colour number + _SysDebug("TODO: \\e]%i;c; Support X properties", Ps); + st->Mode = MODE_STRING; + st->StringType = STRING_IGNORE; + break; + case 10: // Change foreground to Pt + case 11: // Change background to Pt + case 52: + // TODO: Can be Pt = [cps01234567]*; + // > Clipboard data in base-64, cut/primary/select buffers 0-7 + // > ='?' returns the clipbard in the same format + default: + _SysDebug("Unknown VT100 OSC \\e]%i;", Ps); + st->Mode = MODE_STRING; + st->StringType = STRING_IGNORE; + break; + } + return ofs; +} +