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

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