1a51a58315e23c50f2eaae1e23cb46eca723d741
[tpg/acess2.git] / KernelLand / Kernel / drv / vterm_vt100.c
1 /*
2  * Acess2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * drv/vterm_vt100.c
6  * - Virtual Terminal - VT100 (Kinda) Emulation
7  */
8 #include "vterm.h"
9
10 // === CONSTANTS ===
11 const Uint16    caVT100Colours[] = {
12                 // Black, Red, Green, Yellow, Blue, Purple, Cyan, Gray
13                 // Same again, but bright
14                 VT_COL_BLACK, 0x700, 0x070, 0x770, 0x007, 0x707, 0x077, 0xAAA,
15                 VT_COL_GREY, 0xF00, 0x0F0, 0xFF0, 0x00F, 0xF0F, 0x0FF, VT_COL_WHITE
16         };
17
18 // === CODE ===
19 /**
20  * \brief Handle a standard large escape code
21  * 
22  * Handles any escape code of the form \x1B[n,...A where n is an integer
23  * and A is any letter.
24  */
25 void VT_int_ParseEscape_StandardLarge(tVTerm *Term, char CmdChar, int argc, int *args)
26 {
27          int    tmp = 1;
28         switch(CmdChar)
29         {
30         // Left
31         case 'D':
32                 tmp = -1;
33         // Right
34         case 'C':
35                 if(argc == 1)   tmp *= args[0];
36                 if( Term->Flags & VT_FLAG_ALTBUF )
37                 {
38                         if( (Term->AltWritePos + tmp) % Term->TextWidth == 0 ) {
39                                 Term->AltWritePos -= Term->AltWritePos % Term->TextWidth;
40                                 Term->AltWritePos += Term->TextWidth - 1;
41                         }
42                         else
43                                 Term->AltWritePos += tmp;
44                 }
45                 else
46                 {
47                         if( (Term->WritePos + tmp) % Term->TextWidth == 0 ) {
48                                 Term->WritePos -= Term->WritePos % Term->TextWidth;
49                                 Term->WritePos += Term->TextWidth - 1;
50                         }
51                         else
52                                 Term->WritePos += tmp;
53                 }
54                 break;
55         
56         // Erase
57         case 'J':
58                 switch(args[0])
59                 {
60                 case 0: // Erase below
61                         break;
62                 case 1: // Erase above
63                         break;
64                 case 2: // Erase all
65                         if( Term->Flags & VT_FLAG_ALTBUF )
66                         {
67                                  int    i = Term->TextHeight;
68                                 while( i-- )    VT_int_ClearLine(Term, i);
69                                 Term->AltWritePos = 0;
70                                 VT_int_UpdateScreen(Term, 1);
71                         }
72                         else
73                         {
74                                  int    i = Term->TextHeight * (giVT_Scrollback + 1);
75                                 while( i-- )    VT_int_ClearLine(Term, i);
76                                 Term->WritePos = 0;
77                                 Term->ViewPos = 0;
78                                 VT_int_UpdateScreen(Term, 1);
79                         }
80                         break;
81                 }
82                 break;
83         
84         // Erase in line
85         case 'K':
86                 switch(args[0])
87                 {
88                 case 0: // Erase to right
89                         if( Term->Flags & VT_FLAG_ALTBUF )
90                         {
91                                  int    i, max;
92                                 max = Term->Width - Term->AltWritePos % Term->Width;
93                                 for( i = 0; i < max; i ++ )
94                                         Term->AltBuf[Term->AltWritePos+i].Ch = 0;
95                         }
96                         else
97                         {
98                                  int    i, max;
99                                 max = Term->Width - Term->WritePos % Term->Width;
100                                 for( i = 0; i < max; i ++ )
101                                         Term->Text[Term->WritePos+i].Ch = 0;
102                         }
103                         VT_int_UpdateScreen(Term, 0);
104                         break;
105                 case 1: // Erase to left
106                         if( Term->Flags & VT_FLAG_ALTBUF )
107                         {
108                                  int    i = Term->AltWritePos % Term->Width;
109                                 while( i -- )
110                                         Term->AltBuf[Term->AltWritePos++].Ch = 0;
111                         }
112                         else
113                         {
114                                  int    i = Term->WritePos % Term->Width;
115                                 while( i -- )
116                                         Term->Text[Term->WritePos++].Ch = 0;
117                         }
118                         VT_int_UpdateScreen(Term, 0);
119                         break;
120                 case 2: // Erase all
121                         if( Term->Flags & VT_FLAG_ALTBUF )
122                         {
123                                 VT_int_ClearLine(Term, Term->AltWritePos / Term->Width);
124                         }
125                         else
126                         {
127                                 VT_int_ClearLine(Term, Term->WritePos / Term->Width);
128                         }
129                         VT_int_UpdateScreen(Term, 0);
130                         break;
131                 }
132                 break;
133         
134         // Set cursor position
135         case 'H':
136                 if( Term->Flags & VT_FLAG_ALTBUF )
137                         Term->AltWritePos = args[1] + args[0]*Term->TextWidth;
138                 else
139                         Term->WritePos = args[1] + args[0]*Term->TextWidth;
140                 //Log_Debug("VTerm", "args = {%i, %i}", args[0], args[1]);
141                 break;
142         // Scroll up `n` lines
143         case 'S':
144                 tmp = -1;
145         // Scroll down `n` lines
146         case 'T':
147                 if(argc == 1)   tmp *= args[0];
148                 if( Term->Flags & VT_FLAG_ALTBUF )
149                         VT_int_ScrollText(Term, tmp);
150                 else
151                 {
152                         if(Term->ViewPos/Term->TextWidth + tmp < 0)
153                                 break;
154                         if(Term->ViewPos/Term->TextWidth + tmp  > Term->TextHeight * (giVT_Scrollback + 1))
155                                 break;
156                         
157                         Term->ViewPos += Term->TextWidth*tmp;
158                 }
159                 break;
160         // Set Mode (?)
161         case 'h':
162                 if( argc >= 1 )
163                 {
164                         switch(args[0])
165                         {
166                         case 2: // Keyboard action mode
167                         case 4: // Insert mode
168                         case 12:        // Send/receive
169                         case 20:        // Automatic newline
170                                 break;
171                         default:        // ?
172                                 break;
173                         }
174                 }
175                 break;
176                 
177         // Set Font flags
178         case 'm':
179                 for( ; argc--; )
180                 {
181                          int    colour_idx;
182                         // Flags
183                         if( 0 <= args[argc] && args[argc] <= 8)
184                         {
185                                 switch(args[argc])
186                                 {
187                                 case 0: Term->CurColour = DEFAULT_COLOUR;       break;  // Reset
188                                 case 1: Term->CurColour |= 0x80000000;  break;  // Bright
189                                 case 2: Term->CurColour &= ~0x80000000; break;  // Dim
190                                 }
191                         }
192                         // Foreground Colour
193                         else if(30 <= args[argc] && args[argc] <= 37) {
194                                 // Get colour index, accounting for bright bit
195                                 colour_idx = args[argc]-30 + ((Term->CurColour>>28) & 8);
196                                 Term->CurColour &= 0x8000FFFF;
197                                 Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
198                         }
199                         // Background Colour
200                         else if(40 <= args[argc] && args[argc] <= 47) {
201                                 // Get colour index, accounting for bright bit
202                                 colour_idx = args[argc]-40 + ((Term->CurColour>>12) & 8);
203                                 Term->CurColour &= 0xFFFF8000;
204                                 Term->CurColour |= caVT100Colours[ colour_idx ];
205                         }
206                         // Foreground Colour - bright
207                         else if(90 <= args[argc] && args[argc] <= 97 ) {
208                                 colour_idx = args[argc]-90 + 8;
209                                 Term->CurColour &= 0x8000FFFF;
210                                 Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ] << 16;
211                         }
212                         // Background Colour - bright
213                         else if(100 <= args[argc] && args[argc] <= 107 ) {
214                                 colour_idx = args[argc]-100 + 8;
215                                 Term->CurColour &= 0xFFFF8000;
216                                 Term->CurColour |= (Uint32)caVT100Colours[ colour_idx ];
217                         }
218                         else {
219                                 Log_Warning("VTerm", "Unknown font flag %i", args[argc]);
220                         }
221                 }
222                 break;
223         
224         // Set scrolling region
225         case 'r':
226                 if( argc != 2 ) break;
227                 Term->ScrollTop = args[0];
228                 Term->ScrollHeight = args[1] - args[0];
229                 break;
230
231         // Save cursor position
232         case 's':
233                 if( argc != 0 ) break;
234                 Term->SavedWritePos = (Term->Flags & VT_FLAG_ALTBUF) ? Term->AltWritePos : Term->WritePos;
235                 break;
236
237         // Restore saved cursor position
238         case 'u':
239                 if( argc != 0 ) break;
240                 *((Term->Flags & VT_FLAG_ALTBUF) ? &Term->AltWritePos : &Term->WritePos) = Term->SavedWritePos;
241                 break;
242
243         default:
244                 Log_Warning("VTerm", "Unknown control sequence '\\x1B[%c'", CmdChar);
245                 break;
246         }
247 }
248
249 /**
250  * \fn int VT_int_ParseEscape(tVTerm *Term, const char *Buffer)
251  * \brief Parses a VT100 Escape code
252  */
253 int VT_int_ParseEscape(tVTerm *Term, const char *Buffer, size_t Bytes)
254 {
255         char    c;
256          int    argc = 0, j = 0;
257          int    args[6] = {0,0,0,0};
258          int    bQuestionMark = 0;
259         const int       ofs = Term->EscapeCodeLen;
260         const int       sparespace = sizeof(Term->EscapeCodeCache)-Term->EscapeCodeLen;
261         const int       copysize = MIN(Bytes, sparespace);
262
263         memcpy( Term->EscapeCodeCache + Term->EscapeCodeLen, Buffer, copysize );
264         Term->EscapeCodeLen += copysize;
265         
266         Bytes = Term->EscapeCodeLen;
267         Buffer = Term->EscapeCodeCache;
268
269         if( Bytes == j )        return j-ofs;
270         c = Buffer[j++];
271         if(c != '\x1b') {
272                 Term->EscapeCodeLen = 0;
273                 return 0;
274         }
275
276         if( Bytes == j )        return j-ofs;
277         c = Buffer[j++];
278
279         switch(c)
280         {
281         //Large Code
282         case '[':
283                 // Get Arguments
284                 if(Bytes == j)  return j-ofs;
285                 c = Buffer[j++];
286                 if(c == '?') {
287                         bQuestionMark = 1;
288                         if(Bytes == j)  return j-ofs;
289                         c = Buffer[j++];
290                 }
291                 if( '0' <= c && c <= '9' )
292                 {
293                         do {
294                                 if(c == ';') {
295                                         if(Bytes == j)  return j-ofs;
296                                         c = Buffer[j++];
297                                 }
298                                 while('0' <= c && c <= '9') {
299                                         args[argc] *= 10;
300                                         args[argc] += c-'0';
301                                         if(Bytes == j)  return j-ofs;
302                                         c = Buffer[j++];
303                                 }
304                                 argc ++;
305                         } while(c == ';');
306                 }
307                 
308                 // Get Command
309                 if( !('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z') )
310                 {
311                         // Error - eat ESC only?
312                         // > j : Entire code skipped
313                         Term->EscapeCodeLen = 0;
314                         return j-ofs;
315                 }
316                 
317                 if( bQuestionMark )
318                 {
319                         switch(c)
320                         {
321                         // DEC Private Mode Set
322                         case 'h':
323                                 if(argc != 1)   break;
324                                 switch(args[0])
325                                 {
326                                 case 25:
327                                         Term->Flags &= ~VT_FLAG_HIDECSR;
328                                         break;
329                                 case 1047:
330                                         VT_int_ToggleAltBuffer(Term, 1);
331                                         break;
332                                 }
333                                 break;
334                         case 'l':
335                                 if(argc != 1)   break;
336                                 switch(args[0])
337                                 {
338                                 case 25:
339                                         Term->Flags |= VT_FLAG_HIDECSR;
340                                         break;
341                                 case 1047:
342                                         VT_int_ToggleAltBuffer(Term, 0);
343                                         break;
344                                 }
345                                 break;
346                         default:
347                                 Log_Warning("VTerm", "Unknown control sequence '\\x1B[?%c'", c);
348                                 break;
349                         }
350                 }
351                 else
352                 {
353                         VT_int_ParseEscape_StandardLarge(Term, c, argc, args);
354                 }
355                 break;
356         case '\0':
357                 // Ignore \0
358                 break;
359         // Reset all attributes
360         case 'c':
361                 Term->CurColour = DEFAULT_COLOUR;
362                 Term->Flags = 0;
363                 Term->ScrollHeight = 0;
364                 break;
365         default:
366                 //Log_Notice("VTerm", "TODO: Handle short escape codes");
367                 {
368                         static volatile int tmp = 0;
369                         if(tmp == 0) {
370                                 tmp = 1;
371                                 Debug("VTerm: Unknown short 0x%x", c);
372                                 tmp = 0;
373                         }
374                 }
375                 break;
376         }
377         
378         //Log_Debug("VTerm", "j = %i, Buffer = '%s'", j, Buffer);
379         Term->EscapeCodeLen = 0;
380         return j-ofs;
381 }

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