3 * - By John Hodge (thePowersGang)
6 * - VT100/xterm Emulation
9 #include "include/vt100.h"
10 #include "include/display.h"
11 #include <ctype.h> // isalpha
13 # define _SysDebug(v...) Debug("VT100 "v)
15 # include <acess/sys.h> // _SysDebug
30 #define FLAG_BOLD 0x01
31 #define FLAG_REVERSE 0x02
37 enum eExcapeMode Mode;
39 enum eStringType StringType;
44 const uint32_t caVT100Colours[] = {
45 // Black, Red, Green, Yellow, Blue, Magenta, Cyan, Gray
46 // Same again, but bright
47 0x000000, 0x770000, 0x007700, 0x777700, 0x000077, 0x770077, 0x007777, 0xAAAAAA,
48 0xCCCCCC, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF,
51 int _locate_eos(size_t Len, const char *Buf);
52 int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buf);
53 int Term_HandleVT100_Short(tTerminal *Term, int Len, const char *Buf);
55 static inline int min(int a, int b)
60 int _locate_eos(size_t Len, const char *Buf)
65 if( Buf[ret] == '\007' )
67 if( Buf[ret] == '\x9c' )
69 if( ret+1 < Len && Buf[ret] == '\x1b' && Buf[ret+1] == '\\' )
75 int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf)
77 #define MAX_VT100_ESCAPE_LEN 16
78 static char inc_buf[MAX_VT100_ESCAPE_LEN];
79 static int inc_len = 0;
80 tVT100State *st = Display_GetTermState(Term);
83 st = malloc( sizeof(*st) );
84 memset(st, 0, sizeof(*st));
85 Display_SetTermState(Term, st);
88 if( st->Mode == MODE_IGNORE ) {
89 st->Mode = MODE_NORMAL;
90 // Used for multi-byte EOS
93 if( st->Mode == MODE_STRING )
95 // We're in a string mode
96 int pos = _locate_eos(Len, Buf);
97 size_t bytes = (pos >= 0 ? pos : Len);
98 char *tmp = realloc(st->StringCache, st->StringLen + bytes+1);
99 if(!tmp) return bytes;
100 memcpy(tmp+st->StringLen, Buf, bytes);
101 tmp[st->StringLen+bytes] = 0;
103 _SysDebug("pos=%i", pos);
104 _SysDebug("'%.*s'", bytes, Buf);
105 // Only apply when we hit EOS at the start
108 switch(st->StringType)
111 Display_SetTitle(Term, st->StringCache);
116 free(st->StringCache);
120 if( *Buf == '\x1b' ) {
121 st->Mode = MODE_IGNORE;
125 st->Mode = MODE_NORMAL;
129 if( inc_len > 0 || *Buf == '\x1b' )
131 // Handle VT100 (like) escape sequence
132 int new_bytes = min(MAX_VT100_ESCAPE_LEN - inc_len, Len);
134 int old_inc_len = inc_len;
135 memcpy(inc_buf + inc_len, Buf, new_bytes);
137 if( new_bytes == 0 ) {
138 _SysDebug("Term_HandleVT100: Hit max? (Len=%i) Flushing cache", Len);
143 inc_len += new_bytes;
144 //_SysDebug("inc_buf = %i '%.*s'", inc_len, inc_len, inc_buf);
147 return 1; // Skip 1 character (the '\x1b')
149 ret = Term_HandleVT100_Short(Term, inc_len, inc_buf);
153 assert(ret > old_inc_len);
154 //_SysDebug("%i bytes of escape code '%.*s' (return %i)",
155 // ret, ret, inc_buf, ret-old_inc_len);
156 ret -= old_inc_len; // counter cached bytes
165 // TODO: Need to handle \t and ^A-Z
167 Display_MoveCursor(Term, 0, -1);
168 Display_AddText(Term, 1, " ");
169 Display_MoveCursor(Term, 0, -1);
172 // TODO: tab (get current cursor pos, space until multiple of 8)
173 _SysDebug("TODO: VT100 Support \\t tab");
176 // TODO: Support disabling CR after NL
177 Display_Newline(Term, 1);
180 if( Len >= 2 && Buf[1] == '\n' ) {
181 // Fast case for \r\n
182 Display_Newline(Term, 1);
185 Display_MoveCursor(Term, 0, INT_MIN);
199 // Force an exit right now
211 int Term_HandleVT100_Short(tTerminal *Term, int Len, const char *Buf)
213 tVT100State *st = Display_GetTermState(Term);
217 case '[': // Multibyte, funtime starts
218 tmp = Term_HandleVT100_Long(Term, Len-2, Buf+2);
224 st->Mode = MODE_STRING;
225 st->StringType = STRING_IGNORE;
226 _SysDebug("TODO: \\e] Support title changes");
229 _SysDebug("TODO: \\e= Application Keypad");
232 _SysDebug("TODO: \\e= Normal Keypad");
235 case '(': // Update G0 charset
237 case ')': // Update G1 charset
245 return 0; // We need more
248 case '0': // DEC Special Character/Linedrawing set
250 case 'B': // US ASCII
254 // xterm C1 \eD and \eM are 'Index' and 'Reverse Index'
255 // - Aparently scroll?
257 // Display_ScrollDown(Term, 1);
261 // Display_ScrollDown(Term, -1);
265 _SysDebug("Unknown VT100 \\e%c", Buf[1]);
270 int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer)
272 tVT100State *st = Display_GetTermState(Term);
275 int args[6] = {0,0,0,0,0,0};
276 int bQuestionMark = 0;
279 if(j == Len) return 0;
283 if(j == Len) return 0;
286 if( '0' <= c && c <= '9' )
290 if(j == Len) return 0;
293 while('0' <= c && c <= '9') {
296 if(j == Len) return 0;
306 _SysDebug("Unexpected char 0x%x in VT100 escape code '\\e[%.*s'", c,
322 case 1: // Aplication cursor keys
323 _SysDebug("TODO: \\e[?1%c Application cursor keys", c);
325 case 25: // Hide cursor
326 _SysDebug("TODO: \\e[?25%c Show/Hide cursor", c);
328 case 1047: // Alternate buffer
329 Display_ShowAltBuffer(Term, set);
331 case 1048: // Save/restore cursor in DECSC
332 _SysDebug("TODO: \\e[?1048%c Save/Restore cursor", c);
334 case 1049: // Save/restore cursor in DECSC and use alternate buffer
335 _SysDebug("TODO: \\e[?1049%c Save/Restore cursor", c);
336 Display_ShowAltBuffer(Term, set);
339 _SysDebug("TODO: \\e[?%i%c Unknow DEC private mode", args[0], c);
344 _SysDebug("Unknown VT100 extended escape char 0x%x", c);
354 Display_MoveCursor(Term, -(argc >= 1 ? args[0] : 1), 0);
357 Display_MoveCursor(Term, (argc >= 1 ? args[0] : 1), 0);
360 Display_MoveCursor(Term, 0, (argc >= 1 ? args[0] : 1));
363 Display_MoveCursor(Term, 0, -(argc >= 1 ? args[0] : 1));
369 Display_SetCursor(Term, args[0], args[1]);
372 case 'J': // Clear lines
376 Display_ClearLines(Term, 1); // Down
379 Display_ClearLines(Term, -1); // Up
382 Display_ClearLines(Term, 0); // All
385 _SysDebug("Unknown VT100 %i J", args[0]);
393 Display_ClearLine(Term, 1);
396 Display_ClearLine(Term, -1);
399 Display_ClearLine(Term, 0);
402 _SysDebug("Unknown VT100 %i K", args[0]);
405 case 'S': // Scroll up n=1
406 Display_ScrollDown(Term, -(argc >= 1 ? args[0] : 1));
408 case 'T': // Scroll down n=1
409 Display_ScrollDown(Term, (argc >= 1 ? args[0] : 1));
415 Display_ResetAttributes(Term);
419 for( int i = 0; i < argc; i ++ )
425 Display_ResetAttributes(Term);
428 st->Flags |= FLAG_BOLD;
429 Display_SetForeground( Term, caVT100Colours[st->CurFG + 8] );
432 _SysDebug("TODO: VT100 \\e[1m - Reverse");
435 st->CurFG = args[i]-30;
439 Display_SetForeground( Term,
440 caVT100Colours[ st->CurFG + (st->Flags&FLAG_BOLD?8:0) ] );
443 st->CurBG = args[i]-40;
447 Display_SetBackground( Term, caVT100Colours[ st->CurBG ] );
450 _SysDebug("TODO: VT100 \\e[%im", args[i]);
456 // Set scrolling region
458 Display_SetScrollArea(Term, args[0], (args[1] - args[0]));
462 Display_SaveCursor(Term);
465 Display_RestoreCursor(Term);
468 _SysDebug("Unknown VT100 long escape char 0x%x '%c'", c, c);