Kernel/VTerm - VT100 emulation fixes exposed by dropbear+irssi
[tpg/acess2.git] / Usermode / Applications / gui_terminal_src / vt100.c
1 /*
2  * Acess GUI Terminal
3  * - By John Hodge (thePowersGang)
4  *
5  * vt100.c
6  * - VT100/xterm Emulation
7  */
8 #include <limits.h>
9 #include "include/vt100.h"
10 #include "include/display.h"
11 #include <ctype.h>      // isalpha
12 #ifdef KERNEL_VERSION
13 # define _SysDebug(v...)        Debug("VT100 "v)
14 #else
15 # include <acess/sys.h> // _SysDebug
16 # include <string.h>
17 # include <assert.h>
18 #endif
19
20 const uint32_t  caVT100Colours[] = {
21         // Black,      Red,    Green,   Yellow,     Blue,  Magenta,     Cyan,      Gray
22         // Same again, but bright
23         0x000000, 0x770000, 0x007700, 0x777700, 0x000077, 0x770077, 0x007777, 0xAAAAAA,
24         0xCCCCCC, 0xFF0000, 0x00FF00, 0xFFFF00, 0x0000FF, 0xFF00FF, 0x00FFFF, 0xFFFFFF, 
25 };
26
27  int    Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buf);
28
29 static inline int min(int a, int b)
30 {
31         return a < b ? a : b;
32 }
33
34 int Term_HandleVT100(tTerminal *Term, int Len, const char *Buf)
35 {
36         #define MAX_VT100_ESCAPE_LEN    16
37         static char     inc_buf[MAX_VT100_ESCAPE_LEN];
38         static int      inc_len = 0;
39
40         if( inc_len > 0 || *Buf == '\x1b' )
41         {
42                 // Handle VT100 (like) escape sequence
43                  int    new_bytes = min(MAX_VT100_ESCAPE_LEN - inc_len, Len);
44                  int    ret = 0;
45                  int    old_inc_len = inc_len;
46                 memcpy(inc_buf + inc_len, Buf, new_bytes);
47
48                 if( new_bytes == 0 ) {
49                         _SysDebug("Term_HandleVT100: Hit max? (Len=%i)", Len);
50                         inc_len = 0;
51                         return 0;
52                 }
53
54                 inc_len += new_bytes;
55                 //_SysDebug("inc_buf = %i '%.*s'", inc_len, inc_len, inc_buf);
56
57                 if( inc_len <= 1 )
58                         return 1;       // Skip 1 character (the '\x1b')
59
60                 switch(inc_buf[1])
61                 {
62                 case '[':       // Multibyte, funtime starts    
63                         ret = Term_HandleVT100_Long(Term, inc_len-2, inc_buf+2);
64                         if( ret > 0 ) {
65                                 ret += 2;
66                         }
67                         break;
68                 case 'D':
69                         Display_ScrollDown(Term, 1);
70                         ret = 2;
71                         break;
72                 case 'M':
73                         Display_ScrollDown(Term, -1);
74                         ret = 2;
75                         break;
76                 default:
77                         ret = 2;
78                         break;
79                 }       
80
81                 if( ret != 0 ) {
82                         inc_len = 0;
83                         assert(ret > old_inc_len);
84                         //_SysDebug("%i bytes of escape code '%.*s' (return %i)",
85                         //      ret, ret, inc_buf, ret-old_inc_len);
86                         ret -= old_inc_len;     // counter cached bytes
87                 }
88                 else
89                         ret = new_bytes;
90                 return ret;
91         }
92
93         switch( *Buf )
94         {
95         // TODO: Need to handle \t and ^A-Z
96         case '\b':
97                 Display_MoveCursor(Term, 0, -1);
98                 Display_AddText(Term, 1, " ");
99                 Display_MoveCursor(Term, 0, -1);
100                 return 1;
101         case '\t':
102                 // TODO: tab (get current cursor pos, space until multiple of 8)
103                 return 1;
104         case '\n':
105                 // TODO: Support disabling CR after NL
106                 Display_Newline(Term, 1);
107                 return 1;
108         case '\r':
109                 if( Len >= 2 && Buf[1] == '\n' ) {
110                         Display_Newline(Term, 1);
111                         return 2;
112                 }
113                 else {
114                         Display_MoveCursor(Term, 0, INT_MIN);
115                         return 1;
116                 }
117         }
118
119          int    ret = 0;
120         while( ret < Len )
121         {
122                 switch(*Buf)
123                 {
124                 case '\x1b':
125                 case '\b':
126                 case '\t':
127                 case '\n':
128                 case '\r':
129                         // Force an exit right now
130                         Len = ret;
131                         break;
132                 default:
133                         ret ++;
134                         Buf ++;
135                         break;
136                 }
137         }
138         return -ret;
139 }
140
141 int Term_HandleVT100_Long(tTerminal *Term, int Len, const char *Buffer)
142 {
143         char    c;
144          int    argc = 0, j = 0;
145          int    args[6] = {0,0,0,0,0,0};
146          int    bQuestionMark = 0;
147         
148         // Get Arguments
149         if(j == Len)    return 0;
150         c = Buffer[j++];
151         if(c == '?') {
152                 bQuestionMark = 1;
153                 if(j == Len)    return 0;
154                 c = Buffer[j++];
155         }
156         if( '0' <= c && c <= '9' )
157         {
158                 do {
159                         if(c == ';') {
160                                 if(j == Len)    return 0;
161                                 c = Buffer[j++];
162                         }
163                         while('0' <= c && c <= '9') {
164                                 args[argc] *= 10;
165                                 args[argc] += c-'0';
166                                 if(j == Len)    return 0;
167                                 c = Buffer[j++];
168                         }
169                         argc ++;
170                 } while(c == ';');
171         }
172         
173         // Get Command
174         if( !isalpha(c) ) {
175                 // Bother.
176                 _SysDebug("Unexpected char 0x%x in VT100 escape code '\\e[%.*s'", c,
177                         Len, Buffer);
178                 return j;
179         }
180
181         if( bQuestionMark )
182         {
183                  int    set = 0;
184                 // Special commands
185                 switch( c )
186                 {
187                 case 'h':       // set
188                         set = 1;
189                 case 'l':       // unset
190                         switch(args[0])
191                         {
192                         case  1:        // Aplication cursor keys
193                                 _SysDebug("TODO: \\e[?1%c Application cursor keys", c);
194                                 break;
195                         case 25:        // Hide cursor
196                                 _SysDebug("TODO: \\e[?25%c Show/Hide cursor", c);
197                                 break;
198                         case 1047:      // Alternate buffer
199                                 Display_ShowAltBuffer(Term, set);
200                                 break;
201                         default:
202                                 _SysDebug("TODO: \\e[?%i%c Unknow DEC private mode", args[0], c);
203                                 break;
204                         }
205                         break;
206                 default:
207                         _SysDebug("Unknown VT100 extended escape char 0x%x", c);
208                         break;
209                 }
210         }
211         else
212         {
213                 // Standard commands
214                 switch( c )
215                 {
216                 case 'A':
217                         Display_MoveCursor(Term, -(argc >= 1 ? args[0] : 1), 0);
218                         break;
219                 case 'B':
220                         Display_MoveCursor(Term, (argc >= 1 ? args[0] : 1), 0);
221                         break;
222                 case 'C':
223                         Display_MoveCursor(Term, 0, (argc >= 1 ? args[0] : 1));
224                         break;
225                 case 'D':
226                         Display_MoveCursor(Term, 0, -(argc >= 1 ? args[0] : 1));
227                         break;
228                 case 'H':
229                         if( argc != 2 ) {
230                         }
231                         else {
232                                 Display_SetCursor(Term, args[0], args[1]);
233                         }
234                         break;
235                 case 'J':       // Clear lines
236                         switch( args[0] )
237                         {
238                         case 0:
239                                 Display_ClearLines(Term, 1);    // Down
240                                 break;
241                         case 1:
242                                 Display_ClearLines(Term, -1);   // Up
243                                 break;
244                         case 2:
245                                 Display_ClearLines(Term, 0);    // All
246                                 break;
247                         default:
248                                 _SysDebug("Unknown VT100 %i J", args[0]);
249                                 break;
250                         }
251                         break;
252                 case 'K':
253                         switch( args[0] )
254                         {
255                         case 0: // To EOL
256                                 Display_ClearLine(Term, -1);
257                                 break;
258                         case 1: // To SOL
259                                 Display_ClearLine(Term, 1);
260                                 break;
261                         case 2:
262                                 Display_ClearLine(Term, 0);
263                                 break;
264                         default:
265                                 _SysDebug("Unknown VT100 %i K", args[0]);
266                                 break;
267                         }
268                 case 'S':       // Scroll down n=1
269                         Display_ScrollDown(Term, -(argc >= 1 ? args[0] : 1));
270                         break;
271                 case 'T':       // Scroll down n=1
272                         Display_ScrollDown(Term, (argc >= 1 ? args[0] : 1));
273                         break;
274                 case 'm':
275                         if( argc == 0 )
276                         {
277                                 // Reset
278                                 Display_ResetAttributes(Term);
279                         }
280                         else
281                         {
282                                 for( int i = 0; i < argc; i ++ )
283                                 {
284                                         switch(args[i])
285                                         {
286                                         case 0:
287                                                 Display_ResetAttributes(Term);
288                                                 break;
289                                         case 1:
290                                                 _SysDebug("TODO: VT100 \\e[1m - Bold");
291                                                 break;
292                                         case 2:
293                                                 _SysDebug("TODO: VT100 \\e[1m - Reverse");
294                                                 break;
295                                         case 30 ... 37:
296                                                 // TODO: Bold/bright
297                                                 Display_SetForeground( Term, caVT100Colours[ args[i]-30 ] );
298                                                 break;
299                                         case 40 ... 47:
300                                                 // TODO: Bold/bright
301                                                 Display_SetBackground( Term, caVT100Colours[ args[i]-40 ] );
302                                                 break;
303                                         default:
304                                                 _SysDebug("TODO: VT100 \\e[%im", args[i]);
305                                                 break;
306                                         } 
307                                 }
308                         }
309                         break;
310                 // Set scrolling region
311                 case 'r':
312                         Display_SetScrollArea(Term, args[0], (args[1] - args[0]));
313                         break;
314                 
315                 case 's':
316                         Display_SaveCursor(Term);
317                         break;
318                 case 'u':
319                         Display_RestoreCursor(Term);
320                         break;
321                 default:
322                         _SysDebug("Unknown VT100 long escape char 0x%x '%c'", c, c);
323                         break;
324                 }
325         }
326         return j;
327 }

UCC git Repository :: git.ucc.asn.au