1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998-2000 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 //GNU General Public License for more details.
17 //You should have received a copy of the GNU General Public License
18 //along with this program; if not, write to the Free Software
19 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 ///////////////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////////////////
28 // Module: ansiprsr.cpp
30 // Contents: ANSI parser base class
34 // Revisions: August 30, 1998 Paul Brannan <pbranna@clemson.edu>
35 // July 29, 1998 pbranna@clemson.edu
36 // June 15, 1998 pbranna@clemson.edu
37 // May 19, 1998 pbranna@clemson.edu
38 // 24 Dec, 1997 Andrey.V.Smilianets
39 // 05. Sep.1997 roryt@hol.gr (I.Ioannou)
40 // 11.May.1997 roryt@hol.gr (I.Ioannou)
41 // 6.April.1997 roryt@hol.gr (I.Ioannou)
42 // 5.April.1997 jbj@nounname.com
43 // 30.M\84rz.1997 Titus_Boxberg@public.uni-hamburg.de
44 // 14.Sept.1996 jbj@nounname.com
47 // 13.Jul.1995 igor.milavec@uni-lj.si
50 ///////////////////////////////////////////////////////////////////////////////
52 //#include <windows.h>
56 const int ANSIColors
[] = {BLACK
, RED
, GREEN
, YELLOW
, BLUE
, MAGENTA
, CYAN
, WHITE
};
58 // The constructor now takes different arguments and initializes different
59 // variables (Paul Brannan 6/15/98)
60 TANSIParser::TANSIParser(TConsole
&RefConsole
, KeyTranslator
&RefKeyTrans
,
61 TScroller
&RefScroller
, TNetwork
&RefNetwork
,
62 TCharmap
&RefCharmap
):
63 TParser(RefConsole
, RefKeyTrans
, RefScroller
, RefNetwork
, RefCharmap
) {
65 iSavedAttributes
= (unsigned char) 7;
66 // must also check to make sure the string is non-NULL
67 // (Paul Brannan 5/8/98)
68 if ((ini
.get_dumpfile() != NULL
) && (*ini
.get_dumpfile() != '\0')){
69 dumpfile
= fopen(ini
.get_dumpfile(), "wb");
76 fast_write
= ini
.get_fast_write(); // Paul Brannan 6/28/98
77 Scroller
.init(&StripBuffer
);
80 TANSIParser::~TANSIParser(){
81 if (dumpfile
) fclose (dumpfile
);
82 // Added I.Ioannou 06 April, 1997
83 if (printfile
!= NULL
) fclose (printfile
);
86 // Created Init() function to initialize the parser but not clear the screen
87 // (Paul Brannan 9/23/98)
88 void TANSIParser::Init() {
89 // Paul Brannan 6/25/98
90 map_G0
= 'B'; map_G1
= 'B';
91 Charmap
.setmap(map_G0
);
99 KeyTrans
.clear_ext_mode();
101 iSavedCurY
= 0; // Reset Variables
104 Console
.SetScroll(-1, -1);
105 Console
.Normal(); // Reset Attributes
111 void TANSIParser::ResetTerminal() {
113 Console
.ClearScreen(); // Clear Screen
114 Console
.SetRawCursorPosition(0,0); // Home Cursor
116 void TANSIParser::SaveCurY(int iY
){
120 void TANSIParser::SaveCurX(int iX
){
124 void TANSIParser::resetTabStops() {
125 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++) {
126 tab_stops
[j
] = 8 + j
- (j
%8);
130 void TANSIParser::ConSetAttribute(unsigned char TextAttrib
){
131 // Paul Brannan 5/8/98
132 // Made this go a little bit faster by changing from switch{} to an array
134 if(TextAttrib
>= 30) {
135 if(TextAttrib
<= 37) {
136 Console
.SetForeground(ANSIColors
[TextAttrib
-30]);
138 } else if((TextAttrib
>= 40) && (TextAttrib
<= 47)) {
139 Console
.SetBackground(ANSIColors
[TextAttrib
-40]);
146 case 0: Console
.Normal(); break; // Normal video
147 case 1: Console
.HighVideo(); break; // High video
148 case 2: Console
.LowVideo(); break; // Low video
149 case 4: Console
.UnderlineOn(); break; // Underline on (I.Ioannou)
150 case 5: Console
.BlinkOn(); break; // Blink video
151 // Corrected by I.Ioannou 11 May, 1997
152 case 7: Console
.ReverseOn(); break; // Reverse video
153 case 8: break; // hidden
154 // All from 10 thru 27 are hacked from linux kernel
155 // I.Ioannou 06 April, 1997
157 // I.Ioannou 04 Sep 1997 turn on/off high bit
160 Charmap
.setmap(current_map
? map_G1
:map_G0
); // Paul Brannan 6/25/98
161 break; // ANSI X3.64-1979 (SCO-ish?)
162 // Select primary font,
163 // don't display control chars
164 // if defined, don't set
165 // bit 8 on output (normal)
169 Charmap
.setmap(0); // Paul Brannan 6/25/98
170 break; // ANSI X3.64-1979 (SCO-ish?)
171 // Select first alternate font,
172 // let chars < 32 be displayed
177 Charmap
.setmap(0); // Paul Brannan 6/25/98
178 break; // ANSI X3.64-1979 (SCO-ish?)
179 // Select second alternate font,
180 // toggle high bit before
181 // displaying as ROM char.
183 case 21: // not really Low video
184 case 22: Console
.LowVideo(); break; // but this works good also
185 case 24: Console
.UnderlineOff(); break; // Underline off
186 case 25: Console
.BlinkOff(); break; // blink off
187 // Corrected by I.Ioannou 11 May, 1997
188 case 27: Console
.ReverseOff(); break; //Reverse video off
190 // Mutt needs this (Paul Brannan, Peter Jordan 12/31/98)
191 // This is from the Linux kernel source
192 case 38: /* ANSI X3.64-1979 (SCO-ish?)
193 * Enables underscore, white foreground
194 * with white underscore (Linux - use
195 * default foreground).
197 Console
.UnderlineOn();
198 Console
.SetForeground(ini
.get_normal_fg());
200 case 39: /* ANSI X3.64-1979 (SCO-ish?)
201 * Disable underline option.
202 * Reset colour to default? It did this
205 Console
.UnderlineOff();
206 Console
.SetForeground(ini
.get_normal_fg());
209 Console
.SetBackground(ini
.get_normal_bg());
215 void TANSIParser::ConSetCursorPos(int x
, int y
) {
217 Console
.SetRawCursorPosition(x
, y
);
219 Console
.SetCursorPosition(x
, y
);
222 const char* TANSIParser::GetTerminalID()
227 // All of the Telnet protocol stuff has been moved to TTelHndl.cpp
228 // This is more consistent with what OO should be
229 // (Paul Brannan 6/15/98)
232 // argsused doesn't work on MSVC++
236 // Use this for the VT100 flags (Paul Brannan 12/2/98)
237 #define FLAG_DOLLAR 0x0001
238 #define FLAG_QMARK 0x0002
239 #define FLAG_GREATER 0x0004
240 #define FLAG_LESS 0x0008
241 #define FLAG_EXCLAM 0x0010
242 #define FLAG_AMPERSAND 0x0020
243 #define FLAG_SLASH 0x0040
244 #define FLAG_EQUAL 0x0080
245 #define FLAG_QUOTE 0x0100
246 #define FLAG_OTHER 0x8000
248 char* TANSIParser::ParseEscapeANSI(char* pszBuffer
, char* pszBufferEnd
)
251 // The buffer contains something like <ESC>[pA
252 // where p is an optional decimal number specifying the count by which the
253 // appropriate action should take place.
254 // The pointer pszBuffer points us to the p, <ESC> and [ are
255 // already 'consumed'
257 // TITUS: Simplification of the code: Assume default count of 1 in case
258 // there are no parameters.
260 const int nParam
= 10; // Maximum number of parameters
261 int iParam
[nParam
] = {1, 0, 0, 0, 0}; // Assume 1 Parameter, Default 1
262 int iCurrentParam
= 0;
264 int missing_param
= 0;
266 // Get parameters from escape sequence.
267 while ((tmpc
= *pszBuffer
) <= '?') {
269 if(tmpc
< '0' || tmpc
> '9') {
270 // Check for parameter delimiter.
272 // This is a hack (Paul Brannan 6/27/98)
273 if(*(pszBuffer
- 1) == '[') missing_param
= iCurrentParam
+1;
278 // It is legal to have control characters inside ANSI sequences
279 // (Paul Brannan 6/26/98)
281 Console
.WriteCtrlChar(tmpc
);
286 // A new way of handling flags (Paul Brannan 12/2/98)
288 case '$': flag
|= FLAG_DOLLAR
; break;
289 case '?': flag
|= FLAG_QMARK
; break;
290 case '>': flag
|= FLAG_GREATER
; break;
291 case '<': flag
|= FLAG_LESS
; break;
292 case '!': flag
|= FLAG_EXCLAM
; break;
293 case '&': flag
|= FLAG_AMPERSAND
; break;
294 case '/': flag
|= FLAG_SLASH
; break;
295 case '=': flag
|= FLAG_EQUAL
; break;
296 case '\"': flag
|= FLAG_QUOTE
; break;
297 default: flag
|= FLAG_OTHER
; break;
303 // Got Numerical Parameter.
304 iParam
[iCurrentParam
] = strtoul(pszBuffer
, &pszBuffer
, 10);
305 if (iCurrentParam
< nParam
)
309 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
310 // So: If there is no digit, assume a count of 1
312 switch ((unsigned char)*pszBuffer
++) {
315 if(iParam
[0] == 0) iParam
[0] = 1; // Paul Brannan 9/1/98
316 Console
.InsertCharacter(iParam
[0]); break;
319 if(iParam
[0] == 0) iParam
[0] = 1;
320 Console
.MoveCursorPosition(0, -iParam
[0]); break;
322 // Added by I.Ioannou 06 April, 1997
325 if(iParam
[0] == 0) iParam
[0] = 1;
326 Console
.MoveCursorPosition(0, iParam
[0]);
328 // Move cursor right.
329 // Added by I.Ioannou 06 April, 1997
332 // Handle cursor size sequences (Jose Cesar Otero Rodriquez and
333 // Paul Brannan, 3/27/1999)
334 if(flag
& FLAG_EQUAL
) {
336 case 7: Console
.SetCursorSize(50); break;
337 case 11: Console
.SetCursorSize(6); break;
338 case 32: Console
.SetCursorSize(0); break;
339 default: Console
.SetCursorSize(13);
342 if(iParam
[0] == 0) iParam
[0] = 1;
343 Console
.MoveCursorPosition(iParam
[0], 0);
348 if(iParam
[0] == 0) iParam
[0] = 1;
349 Console
.MoveCursorPosition(-iParam
[0], 0);
351 // Move cursor to beginning of line, p lines down.
352 // Added by I.Ioannou 06 April, 1997
354 Console
.MoveCursorPosition(-Console
.GetCursorX(), iParam
[0]);
356 // Moves active position to beginning of line, p lines up
357 // Added by I.Ioannou 06 April, 1997
358 // With '=' this changes the default fg color (Paul Brannan 6/27/98)
360 if(flag
& FLAG_EQUAL
)
361 Console
.setDefaultFg(iParam
[0]);
363 Console
.MoveCursorPosition(-Console
.GetCursorX(), -iParam
[0]);
366 // Added by I.Ioannou 06 April, 1997
367 // With '=' this changes the default bg color (Paul Brannan 6/27/98)
369 case 'G': // 'G' is from Linux kernel sources
370 if(flag
& FLAG_EQUAL
) {
371 Console
.setDefaultBg(iParam
[0]);
373 if (iCurrentParam
< 1) // Alter Default
375 // this was backward, and we should subtract 1 from x
376 // (Paul Brannan 5/27/98)
377 ConSetCursorPos(iParam
[0] - 1, Console
.GetCursorY());
380 // Set cursor position.
383 if (iCurrentParam
< 2 || iParam
[1] < 1)
385 ConSetCursorPos(iParam
[1] - 1, iParam
[0] - 1);
389 if ( iCurrentParam
< 1 ) iParam
[0] = 0; // Alter Default
391 case 0: Console
.ClearEOScreen(); break;
392 case 1: Console
.ClearBOScreen(); break;
394 Console
.ClearScreen();
395 Console
.SetRawCursorPosition(0, 0);
401 if (iCurrentParam
< 1) // Alter Default
404 case 0: Console
.ClearEOLine(); break;
405 case 1: Console
.ClearBOLine(); break;
406 case 2: Console
.ClearLine(); break;
409 // Insert p new, blank lines.
410 // Added by I.Ioannou 06 April, 1997
413 // for (int i = 1; i <= iParam[0]; i++)
414 // This should speed things up a bit (Paul Brannan 9/2/98)
415 Console
.ScrollDown(Console
.GetRawCursorY(), -1, iParam
[0]);
419 // Added by I.Ioannou 06 April, 1997
422 for (int i
= 1; i
<= iParam
[0]; i
++)
423 // This should speed things up a bit (Paul Brannan 9/2/98)
424 Console
.ScrollDown(Console
.GetRawCursorY(), -1, -1);
429 Console
.DeleteCharacter(iParam
[0]);
431 // Scrolls screen up (down? -- PB) p lines,
432 // Added by I.Ioannou 06 April, 1997
433 // ANSI X3.64-1979 references this but I didn't
434 // found it in any telnet implementation
435 // note 05 Oct 97 : but SCO terminfo uses them, so uncomment them !!
438 //for (int i = 1; i <= iParam[0]; i++)
439 // This should speed things up a bit (Paul Brannan 9/2/98)
440 Console
.ScrollDown(-1, -1, -iParam
[0]);
443 // Scrolls screen up p lines,
444 // Added by I.Ioannou 06 April, 1997
445 // ANSI X3.64-1979 references this but I didn't
446 // found it in any telnet implementation
447 // note 05 Oct 97 : but SCO terminfo uses them, so uncomment them !!
450 // for (int i = 1; i <= iParam[0]; i++)
451 // This should speed things up a bit (Paul Brannan 9/2/98)
452 Console
.ScrollDown(-1, -1, iParam
[0]);
455 // Erases p characters up to the end of line
456 // Added by I.Ioannou 06 April, 1997
459 int iKeepX
= Console
.GetRawCursorX();
460 int iKeepY
= Console
.GetRawCursorY();
461 if (iParam
[0] > Console
.GetWidth())
462 iParam
[0] = Console
.GetWidth(); // up to the end of line
463 for ( int i
= 1; i
<= iParam
[0]; i
++ )
464 Console
.WriteString(" ", 1);
465 Console
.SetRawCursorPosition(iKeepX
, iKeepY
);
468 // Go back p tab stops
469 // Added by I.Ioannou 06 April, 1997
470 // Implemented by Paul Brannan, 4/13/2000
473 int x
= Console
.GetCursorX();
474 for(int j
= 0; x
> 0 && j
< iParam
[0]; j
++)
475 while(x
> 0 && tab_stops
[j
] == tab_stops
[x
]) x
--;
476 Console
.SetCursorPosition(x
, Console
.GetCursorY());
482 const char* szTerminalId
= GetTerminalID();
483 Network
.WriteString(szTerminalId
, strlen(szTerminalId
));
486 // TITUS++ 2. November 1998: Repeat Character.
488 // isprint may be causing problems (Paul Brannan 3/27/99)
489 // if ( isprint(last_char) ) {
490 char buf
[150]; // at most 1 line (max 132 chars)
492 if ( iParam
[0] > 149 ) iParam
[0] = 149;
493 memset(buf
, last_char
, iParam
[0]);
496 Console
.WriteStringFast(buf
, iParam
[0]);
498 Console
.WriteString(buf
, iParam
[0]);
502 // Added by I.Ioannou 06 April, 1997
504 if (iCurrentParam
< 1) // Alter Default
506 // this was backward, and we should subtract 1 from y
507 // (Paul Brannan 5/27/98)
508 ConSetCursorPos(Console
.GetCursorX(), iParam
[0] - 1);
511 // Added by I.Ioannou 06 April, 1997
513 if (iCurrentParam
< 1) // Alter Default
518 // Clear the horizontal tab stop at the current active position
519 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++) {
520 int x
= Console
.GetCursorX();
521 if(tab_stops
[j
] == x
) tab_stops
[j
] = tab_stops
[x
+ 1];
526 // I think this might be "set as default?"
530 // Clear all tab stops
531 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++)
540 for (int i
= 0; i
< iCurrentParam
; i
++) {
541 // Changed to a switch statement (Paul Brannan 5/27/98)
542 if(flag
& FLAG_QMARK
) {
544 case 1: // App cursor keys
545 KeyTrans
.set_ext_mode(APP_KEY
);
547 case 2: // VT102 mode
549 KeyTrans
.unset_ext_mode(APP2_KEY
);
551 case 3: // 132 columns
552 if(ini
.get_wide_enable()) {
553 Console
.SetWindowSize(132, -1);
556 case 4: // smooth scrolling
558 case 5: // Light background
561 case 6: // Stay in margins
565 Console
.setLineWrap(true);
567 case 8: // Auto-repeat keys
569 case 18: // Send FF to printer
571 case 19: // Entire screen legal for printer
573 case 25: // Visible cursor
575 case 66: // Application numeric keypad
585 case 2: // Lock keyboard
587 case 3: // Act upon control codes (PB 12/5/98)
590 case 4: // Set insert mode
591 Console
.InsertMode(1);
593 case 12: // Local echo off
595 case 20: // Newline sends cr/lf
596 KeyTrans
.set_ext_mode(APP4_KEY
);
611 if (iCurrentParam
< 1)
614 case 0: break; // Print Screen
615 case 1: break; // Print Line
616 // Added I.Ioannou 06 April, 1997
620 if ( printfile
!= NULL
)
625 printfile
= fopen(ini
.get_printer_name(), "ab");
626 if (printfile
!= NULL
) InPrintMode
= 1;
630 // Unset extended mode
633 for (int i
= 0; i
< iCurrentParam
; i
++) {
634 // Changed to a switch statement (Paul Brannan 5/27/98)
635 if(flag
& FLAG_QMARK
) {
637 case 1: // Numeric cursor keys
638 KeyTrans
.unset_ext_mode(APP_KEY
);
642 KeyTrans
.set_ext_mode(APP2_KEY
);
644 case 3: // 80 columns
645 if(ini
.get_wide_enable()) {
646 Console
.SetWindowSize(80, -1);
649 case 4: // jump scrolling
651 case 5: // Dark background
654 case 6: // Ignore margins
658 Console
.setLineWrap(false);
660 case 8: // Auto-repeat keys
662 case 19: // Only send scrolling region to printer
664 case 25: // Invisible cursor
666 case 66: // Numeric keypad
676 case 2: // Unlock keyboard
678 case 3: // Display control codes (PB 12/5/98)
681 case 4: // Set overtype mode
682 Console
.InsertMode(0);
684 case 12: // Local echo on
686 case 20: // sends lf only
687 KeyTrans
.unset_ext_mode(APP4_KEY
);
688 newline_mode
= false;
702 if(missing_param
) Console
.Normal();
703 if(iCurrentParam
== 0) {
706 for(int i
= 0; i
< iCurrentParam
; i
++)
707 ConSetAttribute(iParam
[i
]);
710 // report cursor position Row X Col
712 if (iCurrentParam
== 1 && iParam
[0]==5) {
713 // report the cursor position
714 Network
.WriteString("\x1B[0n", 6);
717 if (iCurrentParam
== 1 && iParam
[0]==6){
718 // report the cursor position
719 // The cursor position needs to be sent as a single string
720 // (Paul Brannan 6/27/98)
721 char szCursorReport
[40] = "\x1B[";
723 itoa(Console
.GetCursorY() + 1,
724 &szCursorReport
[strlen(szCursorReport
)], 10);
725 strcat(szCursorReport
, ";");
726 itoa(Console
.GetCursorX() + 1,
727 &szCursorReport
[strlen(szCursorReport
)], 10);
728 strcat(szCursorReport
, "R");
730 Network
.WriteString(szCursorReport
, strlen(szCursorReport
));
734 // Miscellaneous weird sequences (Paul Brannan 6/27/98)
736 // Set conformance level
737 if(flag
& FLAG_QUOTE
) {
740 // Soft terminal reset
741 if(flag
& FLAG_EXCLAM
) {
744 // Report mode settings
745 if(flag
& FLAG_DOLLAR
) {
751 if (iCurrentParam
< 1) {
752 // Enable scrolling for entire display
753 Console
.SetScroll(-1, -1);
756 if (iCurrentParam
>1) {
757 // Enable scrolling from row1 to row2
758 Console
.SetScroll(iParam
[0] - 1, iParam
[1] - 1);
759 // If the cursor is outside the scrolling range, fix it
760 // (Paul Brannan 6/26/98)
761 // if(Console.GetRawCursorY() < iParam[0] - 1) {
762 // Console.SetRawCursorPosition(Console.GetCursorX(),
765 // if(Console.GetRawCursorY() > iParam[1] - 1) {
766 // Console.SetRawCursorPosition(Console.GetCursorX(),
770 // Move the cursor to the home position (Paul Brannan 12/2/98)
771 Console
.SetCursorPosition(0, 0);
773 // Save cursor position
775 SaveCurY(Console
.GetRawCursorY());
776 SaveCurX(Console
.GetRawCursorX());
778 // Restore cursor position
780 Console
.SetRawCursorPosition(iSavedCurX
, iSavedCurY
);
782 // DEC terminal report (Paul Brannan 6/28/98)
785 Network
.WriteString("\033[3;1;1;128;128;1;0x", 20);
787 Network
.WriteString("\033[2;1;1;128;128;1;0x", 20);
800 // Added by Frediano Ziglio, 5/31/2000
802 // initially copied from ParseEscapeANSI
803 char* TANSIParser::ParseEscapeMTE(char* pszBuffer
, char* pszBufferEnd
)
805 // The buffer contains something like <ESC>~pA
806 // where p is an optional decimal number specifying the count by which the
807 // appropriate action should take place.
808 // The pointer pszBuffer points us to the p, <ESC> and ~ are
809 // already 'consumed'
810 // TITUS: Simplification of the code: Assume default count of 1 in case
811 // there are no parameters.
813 const int nParam
= 10; // Maximum number of parameters
814 int iParam
[nParam
] = {1, 0, 0, 0, 0}; // Assume 1 parameter, Default 1
815 int iCurrentParam
= 0;
818 // Get parameters from escape sequence.
819 while ((tmpc
= *pszBuffer
) <= '?') {
820 if(tmpc
< '0' || tmpc
> '9') {
821 // Check for parameter delimiter.
829 // Got Numerical Parameter.
830 iParam
[iCurrentParam
] = strtoul(pszBuffer
, &pszBuffer
, 10);
831 if (iCurrentParam
< nParam
)
835 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
836 // So: If there is no digit, assume a count of 1
838 switch ((unsigned char)*pszBuffer
++) {
841 if (iCurrentParam
< 2 )
843 if (iParam
[0] <= 15 && iParam
[1] <= 15)
844 Console
.SetAttrib( (iParam
[1] << 4) | iParam
[0] );
850 if (iCurrentParam
< 2 )
852 mteRegionXF
= iParam
[1]-1;
853 mteRegionYF
= iParam
[0]-1;
859 if (mteRegionXF
== -1 || iCurrentParam
< 1)
861 sRepeat
[0] = (char)iParam
[0];
863 int xi
= Console
.GetCursorX(),yi
= Console
.GetCursorY();
864 int xf
= mteRegionXF
;
865 int yf
= mteRegionYF
;
867 for(int y
=yi
;y
<=yf
;++y
)
869 Console
.SetCursorPosition(xi
,y
);
870 for(int x
=xi
;x
<=xf
;++x
)
872 Console
.WriteStringFast(sRepeat
,1);
880 if (mteRegionXF
== -1 || iCurrentParam
< 2)
882 int /*x = Console.GetCursorX(),*/y
= Console
.GetCursorY();
883 // int xf = mteRegionXF;
884 int yf
= mteRegionYF
;
886 // !!! don't use x during scroll
887 int diff
= (iParam
[0]-1)-y
;
889 Console
.ScrollDown(y
-1,yf
,diff
);
891 Console
.ScrollDown(y
,yf
+1,diff
);
894 // Meridian main version ??
896 // disable echo and line mode
897 Network
.set_local_echo(0);
898 Network
.set_line_mode(0);
899 // Meridian Server handle cursor itself
900 Console
.SetCursorSize(0);
905 Network
.WriteString("\033vga.",5);
918 char* TANSIParser::ParseEscape(char* pszBuffer
, char* pszBufferEnd
) {
921 // Check if we have enough characters in buffer.
922 if ((pszBufferEnd
- pszBuffer
) < 2)
925 // I.Ioannou 04 Sep 1997
926 // there is no need for pszBuffer++; after each command
928 // Decode the command.
931 switch (*pszBuffer
++) {
932 case 'A': // Cursor up
933 Console
.MoveCursorPosition(0, -1);
937 Console
.MoveCursorPosition(0, 1);
941 Console
.MoveCursorPosition(1, 0);
943 // LF *or* cursor left (Paul Brannan 6/27/98)
946 Console
.MoveCursorPosition(-1, 0);
950 // CR/LF (Paul Brannan 6/26/98)
952 Console
.WriteCtrlString("\r\n", 2);
954 // Special graphics char set (Paul Brannan 6/27/98)
958 // ASCII char set (Paul Brannan 6/27/98)
962 // Home cursor/tab set
964 if(ini
.get_vt100_mode()) {
965 int x
= Console
.GetCursorX();
967 int t
= tab_stops
[x
- 1];
968 for(int j
= x
- 1; j
>= 0 && tab_stops
[j
] == t
; j
--)
972 // I.Ioannou 04 Sep 1997 (0,0) not (1,1)
973 ConSetCursorPos(0, 0);
976 // Reverse line feed (Paul Brannan 6/27/98)
977 // FIX ME!!! reverse_index is wrong to be calling here
978 // (Paul Brannan 12/2/98)
980 Console
.reverse_index();
982 // Erase end of screen
984 Console
.ClearEOScreen();
988 Console
.ClearEOLine();
990 // Scroll Up one line //Reverse index
992 Console
.reverse_index();
994 // Direct cursor addressing
996 if ((pszBufferEnd
- pszBuffer
) >= 2){
997 // if we subtract '\x1F', then we may end up with a negative
998 // cursor position! (Paul Brannan 6/26/98)
999 ConSetCursorPos(pszBuffer
[1] - ' ', pszBuffer
[0] - ' ');
1002 pszBuffer
--; // Paul Brannan 6/26/98
1005 // Terminal ID Request
1008 const char* szTerminalId
= GetTerminalID();
1009 Network
.WriteString(szTerminalId
, strlen(szTerminalId
));
1012 // reset terminal to defaults
1016 // Enter alternate keypad mode
1018 KeyTrans
.set_ext_mode(APP3_KEY
);
1020 // Exit alternate keypad mode
1022 KeyTrans
.unset_ext_mode(APP3_KEY
);
1026 KeyTrans
.unset_ext_mode(APP2_KEY
); // exit vt52 mode
1028 // Graphics processor on (See note 3)
1031 // Line size commands
1032 case '#': //Line size commands
1033 // (Paul Brannan 6/26/98)
1034 if(pszBuffer
< pszBufferEnd
) {
1035 switch(*pszBuffer
++) {
1036 case '3': break; // top half of a double-height line
1037 case '4': break; // bottom half of a double-height line
1038 case '6': break; // current line becomes double-width
1039 case '8': Console
.ClearScreen('E'); break;
1045 // Graphics processor off (See note 3)
1048 // Save cursor and attribs
1050 SaveCurY(Console
.GetRawCursorY());
1051 SaveCurX(Console
.GetRawCursorX());
1052 iSavedAttributes
= Console
.GetAttrib();
1054 // Restore cursor position and attribs
1056 Console
.SetRawCursorPosition(iSavedCurX
, iSavedCurY
);
1057 Console
.SetAttrib(iSavedAttributes
);
1059 // Set G0 map (Paul Brannan 6/25/98)
1061 if (pszBuffer
< pszBufferEnd
) {
1062 map_G0
= *pszBuffer
;
1063 if(current_map
== 0) Charmap
.setmap(map_G0
);
1069 // Set G1 map (Paul Brannan 6/25/98)
1071 if (pszBuffer
< pszBufferEnd
) {
1072 map_G1
= *pszBuffer
;
1073 if(current_map
== 1) Charmap
.setmap(map_G1
);
1079 // This doesn't do anything, as far as I can tell, but it does take
1080 // a parameter (Paul Brannan 6/27/98)
1082 if (pszBuffer
< pszBufferEnd
) {
1088 // ANSI escape sequence
1090 // Check if we have whole escape sequence in buffer.
1091 // This should not be isalpha anymore (Paul Brannan 9/1/98)
1092 pszChar
= pszBuffer
;
1093 while ((pszChar
< pszBufferEnd
) && (*pszChar
<= '?'))
1095 if (pszChar
== pszBufferEnd
)
1098 pszBuffer
= ParseEscapeANSI(pszBuffer
, pszBufferEnd
);
1102 // Frediano Ziglio, 5/31/2000
1103 // Meridian Terminal Emulator extension
1105 // !!! should put in MTE procedure
1106 pszChar
= pszBuffer
;
1107 while ((pszChar
< pszBufferEnd
) && (*pszChar
<= '?'))
1109 if (pszChar
== pszBufferEnd
)
1112 pszBuffer
= ParseEscapeMTE(pszBuffer
, pszBufferEnd
);
1125 // This function now only parses the ANSI buffer and does not do anything
1126 // with IAC sequences. That code has been moved to TTelHndl.cpp.
1127 // The scroller update routines have been moved to TScroll.cpp.
1128 // (Paul Brannan 6/15/98)
1129 char* TANSIParser::ParseBuffer(char* pszHead
, char* pszTail
){
1130 // copy into ANSI buffer
1133 // Parse the buffer for ANSI or display
1134 while (pszHead
< pszTail
) {
1135 if(!ini
.get_output_redir()) {
1136 pszResult
= ParseANSIBuffer(pszHead
, pszTail
);
1138 // Output is being redirected
1139 if(ini
.get_strip_redir()) {
1140 // Skip the WriteFile() altogether and pass the buffer to a filter
1141 // Mark Miesfield 09/24/2000
1142 pszResult
= PrintGoodChars(pszHead
, pszTail
);
1145 // Paul Brannan 7/29/98
1146 // Note that this has the unforunate effect of printing out
1147 // NULL (ascii 0) characters onto the screen
1148 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE
), pszHead
,
1149 pszTail
- pszHead
, &Result
, NULL
)) pszResult
= pszHead
;
1150 pszResult
= pszHead
+ Result
;
1154 fwrite( pszHead
, sizeof (char), pszResult
-pszHead
, dumpfile
);
1155 if(ini
.get_scroll_enable()) Scroller
.update(pszHead
, pszResult
);
1156 if (pszResult
== pszHead
) break;
1157 pszHead
= pszResult
;
1159 // return the new head to the buffer
1163 // A simple routine to strip ANSI sequences
1164 // This isn't perfect, but it does an okay job (Paul Brannan 7/5/98)
1165 // Fixed a line counting bug (Paul Brannan 12/4/98)
1166 int TANSIParser::StripBuffer(char* pszHead
, char* pszTail
, int width
) {
1167 int lines
= 0, c
= 0;
1168 char *pszBuf
= pszHead
;
1170 while(pszHead
< pszTail
) {
1171 if(iscntrl(*pszHead
)) {
1172 switch(*(pszHead
++)) {
1176 if(!(c
%width
)) lines
--;
1183 *(pszBuf
++) = *(pszHead
- 1);
1187 switch(*(pszHead
++)) {
1188 case 'Y': pszHead
+= 2; break;
1192 case '%': pszHead
++; break;
1194 while((pszHead
< pszTail
) && (*pszHead
< '?'))
1201 *(pszBuf
++) = *(pszHead
++);
1204 if(c
!= 0 && !(c
%width
))
1208 // Fill in the end of the buffer with blanks
1209 while(pszBuf
<= pszTail
) *pszBuf
++ = ' ';
1214 char* TANSIParser::ParseANSIBuffer(char* pszBuffer
, char* pszBufferEnd
)
1217 return PrintBuffer(pszBuffer
, pszBufferEnd
);
1220 unsigned char tmpc
= *(unsigned char *)pszBuffer
;
1223 return ParseEscape(pszBuffer
, pszBufferEnd
);
1226 // if((fast_write && tmpc < 32) ||
1227 // !print_ctrl && (tmpc < 32 || (EightBit_Ansi &&
1228 // (tmpc > 128 && tmpc < 128 + ' ')))) {
1230 // We shouldn't print ctrl characters when fast write is enabled
1231 // and ctrl chars are disabled (Paul Brannan 9/1/98)
1233 // From the Linux kernel (Paul Brannan 12/5/98):
1234 /* A bitmap for codes <32. A bit of 1 indicates that the code
1235 * corresponding to that bit number invokes some special action
1236 * (such as cursor movement) and should not be displayed as a
1237 * glyph unless the disp_ctrl mode is explicitly enabled.
1239 const long CTRL_ACTION
= 0x0d00ff81;
1240 const long CTRL_ALWAYS
= 0x0800f501;
1241 if(!(((print_ctrl
?CTRL_ALWAYS
:CTRL_ACTION
)>>tmpc
)&1)) {
1243 Console
.WriteString((char *)&tmpc
, 1);
1253 // I.Ioannou 5/30/98
1259 // destructive backspace
1261 // Added option for destructive backspace (Paul Brannan 5/13/98)
1262 // Changed to ConWriteCtrlString so that the cursor position can be
1263 // updated (Paul Brannan 5/25/98)
1264 if(ini
.get_dstrbksp()) {
1265 Console
.WriteCtrlChar('\b');
1266 Console
.WriteString(" ", 1);
1267 Console
.WriteCtrlChar('\b');
1269 else Console
.WriteCtrlChar('\b');
1277 int x
= Console
.GetCursorX();
1279 Console
.SetCursorPosition(tab_stops
[x
], Console
.GetCursorY());
1285 // Test for local echo (Paul Brannan 8/25/98)
1286 if(Network
.get_local_echo() || newline_mode
) // &&
1287 Console
.WriteCtrlChar('\x0d');
1288 Console
.WriteCtrlChar('\x0a');
1295 Console
.ClearScreen();
1296 Console
.SetRawCursorPosition(Console
.GetCursorX(), 1); // changed fm 1
1300 Console
.WriteCtrlChar('\x0d');
1305 case 14: // shift out of alternate chararcter set
1307 Charmap
.setmap(map_G1
); // Paul Brannan 6/25/98
1311 case 15: // shift in
1313 Charmap
.setmap(map_G0
); // Paul Brannan 6/25/98
1317 // Paul Brannan 9/1/98 - Is this okay?
1325 // added by I.Ioannou 06 April, 1997
1326 // In 8 bit systems the server may send 0x9b instead of ESC[
1327 // Well, this will produce troubles in Greek 737 Code page
1328 // which uses 0x9b as the small "delta" - and I thing that there
1329 // is another European country with the same problem.
1330 // If we have to stay 8-bit clean we may have to
1331 // give the ability of ROM characters (ESC[11m),
1332 // for striped 8'th bit (ESC[12m) as SCO does,
1333 // or a parameter at compile (or run ?) time.
1334 // We now check for a flag in the ini file (Paul Brannan 5/13/98)
1335 // We also handle any 8-bit ESC sequence (Paul Brannan 6/28/98)
1336 if(ini
.get_eightbit_ansi() && (tmpc
> 128 && tmpc
< 128 + ' ')) {
1337 // There's a chance the sequence might not parse. If this happens
1338 // then pszBuffer will be one character too far back, since
1339 // ParseEscape is expecting two characters, not one.
1340 // In that case we must handle it.
1341 char *pszCurrent
= pszBuffer
;
1342 pszBuffer
= ParseEscape(pszBuffer
, pszBufferEnd
);
1343 if(pszBuffer
< pszCurrent
) pszBuffer
= pszCurrent
;
1346 char* pszCurrent
= pszBuffer
+ 1;
1347 // I.Ioannou 04 Sep 1997 FIXME with ESC[11m must show chars < 32
1348 // Fixed (Paul Brannan 6/28/98)
1349 while ((pszCurrent
< pszBufferEnd
) && (!iscntrl(*pszCurrent
))) {
1350 // I.Ioannou 04 Sep 1997 strip on high bit
1351 if ( (inGraphMode
) && (*pszCurrent
> (char)32) )
1352 *pszCurrent
|= 0x80 ;
1356 // Note that this may break dumpfiles slightly.
1357 // If 'B' is set to anything other than ASCII, this will cause problems
1358 // (Paul Brannan 6/28/98)
1359 if(current_map
!= 'B' && Charmap
.enabled
)
1360 Charmap
.translate_buffer(pszBuffer
, pszCurrent
);
1362 last_char
= *(pszCurrent
-1); // TITUS++: Remember last char
1365 pszBuffer
+= Console
.WriteStringFast(pszBuffer
,
1366 pszCurrent
- pszBuffer
);
1368 pszBuffer
+= Console
.WriteString(pszBuffer
,
1369 pszCurrent
- pszBuffer
);
1375 // Added by I.Ioannou 06 April, 1997
1376 // Print the buffer until you reach ESC[4i
1377 char* TANSIParser::PrintBuffer(char* pszBuffer
, char* pszBufferEnd
) {
1378 // Check if we have enough characters in buffer.
1379 if ((pszBufferEnd
- pszBuffer
) < 4)
1383 tmpChar
= pszBuffer
;
1384 if ( *tmpChar
== 27 ) {
1386 if ( *tmpChar
== '[' ) {
1388 if ( *tmpChar
== '4' ) {
1390 if ( *tmpChar
== 'i' ) {
1391 InPrintMode
= 0; // Stop Print Log
1392 if ( printfile
!= NULL
)
1401 if (printfile
!= NULL
) {
1402 fputc( *pszBuffer
, printfile
);
1410 /* - PrintGoodChars( pszHead, pszTail ) - - - - - - - - - - - - - - - - - - -
1413 Mark Miesfield 09/24/2000
1415 Prints the characters in a buffer, from the specified head to the specified
1416 tail, to standard out, skipping any control characters or ANSI escape
1419 Parameters on entry:
1420 pszHead -> Starting point in buffer.
1422 pszTail -> Ending point in buffer.
1425 Pointer to the first character in the buffer that was not output to
1426 standard out. (Since no error checking is done, this is in effect
1431 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1433 char * TANSIParser::PrintGoodChars( char * pszHead
, char * pszTail
) {
1435 while ( pszHead
< pszTail
) {
1436 if ( iscntrl( *pszHead
) ) {
1437 switch ( *(pszHead
++) ) {
1447 switch ( *(pszHead
++) ) {
1455 case '%': pszHead
++; break;
1457 while ( (pszHead
< pszTail
) && (*pszHead
< '?') )
1472 putc( *(pszHead
++), stdout
);
1476 // End of function: PrintGoodChars( pszHead, pszTail )