:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / apps / utils / net / telnet / ansi.cpp
1 /* $Id$
2  *
3  * FILE       : ansi.cpp
4  * AUTHOR     : unknown (sources found on www.telnet.org)
5  * PROJECT    : ReactOS Operating System
6  * DESCRIPTION: telnet client for the W32 subsystem
7  * DATE       : 2001-01-21
8  * REVISIONS
9  *      2001-02-21 ea   Modified to compile under 0.0.16 src tree
10  */
11 #include <winsock.h>
12 #include <windows.h>
13
14 #include "telnet.h"
15
16 // Need to implement a Keymapper.
17 // here are some example key maps
18
19 // vt100 f1 - \eOP
20 // vt100 f2 - \eOQ
21
22 // ansi  f5 - \e[17~
23 //       f6 - \e[18~
24 //       f7 - \e[20~
25 //       f10- \e[[V
26
27 enum _ansi_state
28 {
29   as_normal,
30   as_esc,
31   as_esc1
32 };
33
34 //SetConsoleMode
35
36 ///////////////////////////////////////////////////////////////////////////////
37 // SET SCREEN ATTRIBUTE
38 /*
39 ESC [ Ps..Ps m  Ps refers to selective parameter. Multiple parameters are
40                 separated by the semicolon character (073 octal). The param-
41                 eters are executed in order and have the following meaning:
42
43                 0 or none               All attributes off
44                 1                       Bold on
45                 4                       Underscore on
46                 5                       Blink on
47                 7                       Reverse video on
48
49                 3x                      set foreground color to x
50                 nx                      set background color to x
51
52                 Any other parameters are ignored.
53 */
54 static int sa = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
55
56 void ansi_set_screen_attribute(char* buffer)
57 {
58   while(*buffer)
59   {
60     switch(*buffer++)
61     {
62     case '0': //Normal
63       sa = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
64       break;
65     case '1': //Hign Intensity
66       sa |= FOREGROUND_INTENSITY;
67       break;
68     case '4': //Underscore
69       break;
70     case '5': //Blink.
71       sa |= BACKGROUND_INTENSITY;
72       break;
73     case '7':
74       sa = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
75       break;
76     case '8':
77       sa = 0;
78       break;
79     case '3':
80       sa = sa & (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY) |
81         (*buffer & 1)?FOREGROUND_RED:0 |
82         (*buffer & 2)?FOREGROUND_GREEN:0 |
83         (*buffer & 4)?FOREGROUND_BLUE:0;
84       if(*buffer)
85         buffer++;
86       break;
87     case '6':
88       sa = sa & (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY) |
89         (*buffer & 1)?BACKGROUND_RED:0 |
90         (*buffer & 2)?BACKGROUND_GREEN:0 |
91         (*buffer & 4)?BACKGROUND_BLUE:0;
92       if(*buffer)
93         buffer++;
94       break;
95     }
96     if(*buffer && *buffer == ';')
97       buffer++;
98   }
99   SetConsoleTextAttribute(StandardOutput,sa);
100 }
101
102 ///////////////////////////////////////////////////////////////////////////////
103 // ERASE LINE
104 /*
105 ESC [ 0K        Same *default*
106 ESC [ 1K        Erase from beginning of line to cursor
107 ESC [ 2K        Erase line containing cursor
108 */
109
110 void ansi_erase_line(char* buffer)
111 {
112   int act = 0;
113   while(*buffer)
114   {
115     act = (*buffer++) - '0';
116   }
117
118   CONSOLE_SCREEN_BUFFER_INFO csbi;
119   GetConsoleScreenBufferInfo(StandardOutput,&csbi);
120
121   COORD pos;
122   DWORD n;
123
124   switch(act)
125   {
126   case 0: //erase to end of line
127     pos.X = csbi.dwCursorPosition.X;
128     pos.Y = csbi.dwCursorPosition.Y;
129     n = csbi.dwSize.X - csbi.dwCursorPosition.X;
130     break;
131   case 1: //erase from beginning
132     pos.X = 0;
133     pos.Y = csbi.dwCursorPosition.Y;
134     n = csbi.dwCursorPosition.X;
135     break;
136   case 2: // erase whole line
137     pos.X = 0;
138     pos.Y = csbi.dwCursorPosition.Y;
139     n = csbi.dwSize.X;
140     break;
141   }
142
143   DWORD w;
144   FillConsoleOutputCharacter(StandardOutput,' ',n,pos,&w);
145 }
146
147
148 ///////////////////////////////////////////////////////////////////////////////
149 // SET POSITION
150 // ESC [ Pl;PcH    Direct cursor addressing, where Pl is line#, Pc is column#
151 // default = (1,1)
152
153 void ansi_set_position(char* buffer)
154 {
155   COORD pos = {0,0};
156
157   // Grab line
158   while(*buffer && *buffer != ';')
159     pos.Y = pos.Y*10 + *buffer++ - '0';
160
161   if(*buffer)
162     buffer++;
163
164   // Grab y
165   while(*buffer && *buffer != ';')
166     pos.X = pos.X*10 + *buffer++ - '0';
167
168   (pos.X)?pos.X--:0;
169   (pos.Y)?pos.Y--:0;
170
171   SetConsoleCursorPosition(StandardOutput,pos);
172  
173 }
174
175 ///////////////////////////////////////////////////////////////////////////////
176 // ERASE SCREEN
177 /*
178 ESC [ 0J        Same *default*
179 ESC [ 2J        Erase entire screen
180 */
181
182 void ansi_erase_screen(char* buffer)
183 {
184   int act = 0;
185   while(*buffer)
186   {
187     act = (*buffer++) - '0';
188   }
189
190   CONSOLE_SCREEN_BUFFER_INFO csbi;
191   GetConsoleScreenBufferInfo(StandardOutput,&csbi);
192
193   COORD pos;
194   DWORD n;
195
196   switch(act)
197   {
198   case 0:
199     pos.X = csbi.dwCursorPosition.X;
200     pos.Y = csbi.dwCursorPosition.Y;
201     n = csbi.dwSize.X*csbi.dwSize.Y;
202     break;
203   case 2:
204     pos.X = 0;
205     pos.Y = 0;
206     n = csbi.dwSize.X*csbi.dwSize.Y;
207     break;
208   }
209
210   DWORD w;
211   FillConsoleOutputCharacter(StandardOutput,' ',n,pos,&w);
212   SetConsoleCursorPosition(StandardOutput,pos);
213 }
214
215 ///////////////////////////////////////////////////////////////////////////////
216 // MOVE UP
217 // ESC [ Pn A      Cursor up Pn lines (Pn default=1)
218
219 void ansi_move_up(char* buffer)
220 {
221   int cnt = *buffer?0:1;
222   while(*buffer)
223   {
224     cnt = cnt*10 + (*buffer++) - '0';
225   }
226
227   COORD pos;
228
229   CONSOLE_SCREEN_BUFFER_INFO csbi;
230   GetConsoleScreenBufferInfo(StandardOutput,&csbi);
231
232   pos.X = csbi.dwCursorPosition.X;
233   pos.Y = ((csbi.dwCursorPosition.Y-cnt)>=0)?(csbi.dwCursorPosition.Y-cnt):0;
234
235   SetConsoleCursorPosition(StandardOutput,pos);
236 }
237
238 ///////////////////////////////////////////////////////////////////////////////
239 char codebuf[256];
240 unsigned char codeptr;
241
242 #define NUM_CODEC 6
243
244 typedef void (*LPCODEPROC)(char*);
245
246 struct 
247 {
248   unsigned char cmd;
249   LPCODEPROC proc;
250 } codec[NUM_CODEC] = {
251   {'m',ansi_set_screen_attribute},
252   {'H',ansi_set_position},
253   {'K',ansi_erase_line},
254   {'J',ansi_erase_screen},
255   {'A',ansi_move_up},
256   {0,0}
257 };
258
259 void ansi(SOCKET server,unsigned char data)
260 {
261   static _ansi_state state = as_normal;
262   DWORD z;
263   switch( state)
264   {
265   case as_normal:
266     switch(data)
267     {
268     case 0:  //eat null codes.
269       break;
270     case 27: //ANSI esc.
271       state = as_esc;
272       break;
273     default: //Send all else to the console.
274       WriteConsole(StandardOutput,&data,1,&z,NULL);
275       break;
276     }
277     break;
278   case as_esc:
279     state = as_esc1;
280     codeptr=0;
281     codebuf[codeptr] = 0;
282     break;
283   case as_esc1:
284     if(data > 64)
285     {
286       int i = 0;
287       codebuf[codeptr] = 0;
288       for(i=0; codec[i].cmd && codec[i].cmd != data; i++);
289       if(codec[i].proc)
290         codec[i].proc(codebuf);
291 #ifdef _DEBUG
292       else
293       {
294         char buf[256];
295         wsprintf(buf,"Unknown Ansi code:'%c' (%s)\n",data,codebuf);
296         OutputDebugString(buf);
297       }
298 #endif
299       state = as_normal;
300     }
301     else
302       codebuf[codeptr++] = data;
303     break;
304   }
305 }
306
307 /* EOF */