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>
55 const int ANSIColors
[] = {BLACK
, RED
, GREEN
, YELLOW
, BLUE
, MAGENTA
, CYAN
, WHITE
};
57 // The constructor now takes different arguments and initializes different
58 // variables (Paul Brannan 6/15/98)
59 TANSIParser::TANSIParser(TConsole
&RefConsole
, KeyTranslator
&RefKeyTrans
,
60 TScroller
&RefScroller
, TNetwork
&RefNetwork
,
61 TCharmap
&RefCharmap
):
62 TParser(RefConsole
, RefKeyTrans
, RefScroller
, RefNetwork
, RefCharmap
) {
64 iSavedAttributes
= (unsigned char) 7;
65 // must also check to make sure the string is non-NULL
66 // (Paul Brannan 5/8/98)
67 if ((ini
.get_dumpfile() != NULL
) && (*ini
.get_dumpfile() != '\0')){
68 dumpfile
= fopen(ini
.get_dumpfile(), "wb");
75 fast_write
= ini
.get_fast_write(); // Paul Brannan 6/28/98
76 Scroller
.init(&StripBuffer
);
79 TANSIParser::~TANSIParser(){
80 if (dumpfile
) fclose (dumpfile
);
81 // Added I.Ioannou 06 April, 1997
82 if (printfile
!= NULL
) fclose (printfile
);
85 // Created Init() function to initialize the parser but not clear the screen
86 // (Paul Brannan 9/23/98)
87 void TANSIParser::Init() {
88 // Paul Brannan 6/25/98
89 map_G0
= 'B'; map_G1
= 'B';
90 Charmap
.setmap(map_G0
);
98 KeyTrans
.clear_ext_mode();
100 iSavedCurY
= 0; // Reset Variables
103 Console
.SetScroll(-1, -1);
104 Console
.Normal(); // Reset Attributes
110 void TANSIParser::ResetTerminal() {
112 Console
.ClearScreen(); // Clear Screen
113 Console
.SetRawCursorPosition(0,0); // Home Cursor
115 void TANSIParser::SaveCurY(int iY
){
119 void TANSIParser::SaveCurX(int iX
){
123 void TANSIParser::resetTabStops() {
124 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++) {
125 tab_stops
[j
] = 8 + j
- (j
%8);
129 void TANSIParser::ConSetAttribute(unsigned char TextAttrib
){
130 // Paul Brannan 5/8/98
131 // Made this go a little bit faster by changing from switch{} to an array
133 if(TextAttrib
>= 30) {
134 if(TextAttrib
<= 37) {
135 Console
.SetForeground(ANSIColors
[TextAttrib
-30]);
137 } else if((TextAttrib
>= 40) && (TextAttrib
<= 47)) {
138 Console
.SetBackground(ANSIColors
[TextAttrib
-40]);
145 case 0: Console
.Normal(); break; // Normal video
146 case 1: Console
.HighVideo(); break; // High video
147 case 2: Console
.LowVideo(); break; // Low video
148 case 4: Console
.UnderlineOn(); break; // Underline on (I.Ioannou)
149 case 5: Console
.BlinkOn(); break; // Blink video
150 // Corrected by I.Ioannou 11 May, 1997
151 case 7: Console
.ReverseOn(); break; // Reverse video
152 case 8: break; // hidden
153 // All from 10 thru 27 are hacked from linux kernel
154 // I.Ioannou 06 April, 1997
156 // I.Ioannou 04 Sep 1997 turn on/off high bit
159 Charmap
.setmap(current_map
? map_G1
:map_G0
); // Paul Brannan 6/25/98
160 break; // ANSI X3.64-1979 (SCO-ish?)
161 // Select primary font,
162 // don't display control chars
163 // if defined, don't set
164 // bit 8 on output (normal)
168 Charmap
.setmap(0); // Paul Brannan 6/25/98
169 break; // ANSI X3.64-1979 (SCO-ish?)
170 // Select first alternate font,
171 // let chars < 32 be displayed
176 Charmap
.setmap(0); // Paul Brannan 6/25/98
177 break; // ANSI X3.64-1979 (SCO-ish?)
178 // Select second alternate font,
179 // toggle high bit before
180 // displaying as ROM char.
182 case 21: // not really Low video
183 case 22: Console
.LowVideo(); break; // but this works good also
184 case 24: Console
.UnderlineOff(); break; // Underline off
185 case 25: Console
.BlinkOff(); break; // blink off
186 // Corrected by I.Ioannou 11 May, 1997
187 case 27: Console
.ReverseOff(); break; //Reverse video off
189 // Mutt needs this (Paul Brannan, Peter Jordan 12/31/98)
190 // This is from the Linux kernel source
191 case 38: /* ANSI X3.64-1979 (SCO-ish?)
192 * Enables underscore, white foreground
193 * with white underscore (Linux - use
194 * default foreground).
196 Console
.UnderlineOn();
197 Console
.SetForeground(ini
.get_normal_fg());
199 case 39: /* ANSI X3.64-1979 (SCO-ish?)
200 * Disable underline option.
201 * Reset colour to default? It did this
204 Console
.UnderlineOff();
205 Console
.SetForeground(ini
.get_normal_fg());
208 Console
.SetBackground(ini
.get_normal_bg());
214 void TANSIParser::ConSetCursorPos(int x
, int y
) {
216 Console
.SetRawCursorPosition(x
, y
);
218 Console
.SetCursorPosition(x
, y
);
221 const char* TANSIParser::GetTerminalID()
226 // All of the Telnet protocol stuff has been moved to TTelHndl.cpp
227 // This is more consistent with what OO should be
228 // (Paul Brannan 6/15/98)
231 // argsused doesn't work on MSVC++
235 // Use this for the VT100 flags (Paul Brannan 12/2/98)
236 #define FLAG_DOLLAR 0x0001
237 #define FLAG_QMARK 0x0002
238 #define FLAG_GREATER 0x0004
239 #define FLAG_LESS 0x0008
240 #define FLAG_EXCLAM 0x0010
241 #define FLAG_AMPERSAND 0x0020
242 #define FLAG_SLASH 0x0040
243 #define FLAG_EQUAL 0x0080
244 #define FLAG_QUOTE 0x0100
245 #define FLAG_OTHER 0x8000
247 char* TANSIParser::ParseEscapeANSI(char* pszBuffer
, char* pszBufferEnd
)
250 // The buffer contains something like <ESC>[pA
251 // where p is an optional decimal number specifying the count by which the
252 // appropriate action should take place.
253 // The pointer pszBuffer points us to the p, <ESC> and [ are
254 // already 'consumed'
256 // TITUS: Simplification of the code: Assume default count of 1 in case
257 // there are no parameters.
259 const int nParam
= 10; // Maximum number of parameters
260 int iParam
[nParam
] = {1, 0, 0, 0, 0}; // Assume 1 Parameter, Default 1
261 int iCurrentParam
= 0;
263 int missing_param
= 0;
265 // Get parameters from escape sequence.
266 while ((tmpc
= *pszBuffer
) <= '?') {
268 if(tmpc
< '0' || tmpc
> '9') {
269 // Check for parameter delimiter.
271 // This is a hack (Paul Brannan 6/27/98)
272 if(*(pszBuffer
- 1) == '[') missing_param
= iCurrentParam
+1;
277 // It is legal to have control characters inside ANSI sequences
278 // (Paul Brannan 6/26/98)
280 Console
.WriteCtrlChar(tmpc
);
285 // A new way of handling flags (Paul Brannan 12/2/98)
287 case '$': flag
|= FLAG_DOLLAR
; break;
288 case '?': flag
|= FLAG_QMARK
; break;
289 case '>': flag
|= FLAG_GREATER
; break;
290 case '<': flag
|= FLAG_LESS
; break;
291 case '!': flag
|= FLAG_EXCLAM
; break;
292 case '&': flag
|= FLAG_AMPERSAND
; break;
293 case '/': flag
|= FLAG_SLASH
; break;
294 case '=': flag
|= FLAG_EQUAL
; break;
295 case '\"': flag
|= FLAG_QUOTE
; break;
296 default: flag
|= FLAG_OTHER
; break;
302 // Got Numerical Parameter.
303 iParam
[iCurrentParam
] = strtoul(pszBuffer
, &pszBuffer
, 10);
304 if (iCurrentParam
< nParam
)
308 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
309 // So: If there is no digit, assume a count of 1
311 switch ((unsigned char)*pszBuffer
++) {
314 if(iParam
[0] == 0) iParam
[0] = 1; // Paul Brannan 9/1/98
315 Console
.InsertCharacter(iParam
[0]); break;
318 if(iParam
[0] == 0) iParam
[0] = 1;
319 Console
.MoveCursorPosition(0, -iParam
[0]); break;
321 // Added by I.Ioannou 06 April, 1997
324 if(iParam
[0] == 0) iParam
[0] = 1;
325 Console
.MoveCursorPosition(0, iParam
[0]);
327 // Move cursor right.
328 // Added by I.Ioannou 06 April, 1997
331 // Handle cursor size sequences (Jose Cesar Otero Rodriquez and
332 // Paul Brannan, 3/27/1999)
333 if(flag
& FLAG_EQUAL
) {
335 case 7: Console
.SetCursorSize(50); break;
336 case 11: Console
.SetCursorSize(6); break;
337 case 32: Console
.SetCursorSize(0); break;
338 default: Console
.SetCursorSize(13);
341 if(iParam
[0] == 0) iParam
[0] = 1;
342 Console
.MoveCursorPosition(iParam
[0], 0);
347 if(iParam
[0] == 0) iParam
[0] = 1;
348 Console
.MoveCursorPosition(-iParam
[0], 0);
350 // Move cursor to beginning of line, p lines down.
351 // Added by I.Ioannou 06 April, 1997
353 Console
.MoveCursorPosition(-Console
.GetCursorX(), iParam
[0]);
355 // Moves active position to beginning of line, p lines up
356 // Added by I.Ioannou 06 April, 1997
357 // With '=' this changes the default fg color (Paul Brannan 6/27/98)
359 if(flag
& FLAG_EQUAL
)
360 Console
.setDefaultFg(iParam
[0]);
362 Console
.MoveCursorPosition(-Console
.GetCursorX(), -iParam
[0]);
365 // Added by I.Ioannou 06 April, 1997
366 // With '=' this changes the default bg color (Paul Brannan 6/27/98)
368 case 'G': // 'G' is from Linux kernel sources
369 if(flag
& FLAG_EQUAL
) {
370 Console
.setDefaultBg(iParam
[0]);
372 if (iCurrentParam
< 1) // Alter Default
374 // this was backward, and we should subtract 1 from x
375 // (Paul Brannan 5/27/98)
376 ConSetCursorPos(iParam
[0] - 1, Console
.GetCursorY());
379 // Set cursor position.
382 if (iCurrentParam
< 2 || iParam
[1] < 1)
384 ConSetCursorPos(iParam
[1] - 1, iParam
[0] - 1);
388 if ( iCurrentParam
< 1 ) iParam
[0] = 0; // Alter Default
390 case 0: Console
.ClearEOScreen(); break;
391 case 1: Console
.ClearBOScreen(); break;
393 Console
.ClearScreen();
394 Console
.SetRawCursorPosition(0, 0);
400 if (iCurrentParam
< 1) // Alter Default
403 case 0: Console
.ClearEOLine(); break;
404 case 1: Console
.ClearBOLine(); break;
405 case 2: Console
.ClearLine(); break;
408 // Insert p new, blank lines.
409 // Added by I.Ioannou 06 April, 1997
412 // for (int i = 1; i <= iParam[0]; i++)
413 // This should speed things up a bit (Paul Brannan 9/2/98)
414 Console
.ScrollDown(Console
.GetRawCursorY(), -1, iParam
[0]);
418 // Added by I.Ioannou 06 April, 1997
421 for (int i
= 1; i
<= iParam
[0]; i
++)
422 // This should speed things up a bit (Paul Brannan 9/2/98)
423 Console
.ScrollDown(Console
.GetRawCursorY(), -1, -1);
428 Console
.DeleteCharacter(iParam
[0]);
430 // Scrolls screen up (down? -- PB) p lines,
431 // Added by I.Ioannou 06 April, 1997
432 // ANSI X3.64-1979 references this but I didn't
433 // found it in any telnet implementation
434 // note 05 Oct 97 : but SCO terminfo uses them, so uncomment them !!
437 //for (int i = 1; i <= iParam[0]; i++)
438 // This should speed things up a bit (Paul Brannan 9/2/98)
439 Console
.ScrollDown(-1, -1, -iParam
[0]);
442 // Scrolls screen up p lines,
443 // Added by I.Ioannou 06 April, 1997
444 // ANSI X3.64-1979 references this but I didn't
445 // found it in any telnet implementation
446 // note 05 Oct 97 : but SCO terminfo uses them, so uncomment them !!
449 // for (int i = 1; i <= iParam[0]; i++)
450 // This should speed things up a bit (Paul Brannan 9/2/98)
451 Console
.ScrollDown(-1, -1, iParam
[0]);
454 // Erases p characters up to the end of line
455 // Added by I.Ioannou 06 April, 1997
458 int iKeepX
= Console
.GetRawCursorX();
459 int iKeepY
= Console
.GetRawCursorY();
460 if (iParam
[0] > Console
.GetWidth())
461 iParam
[0] = Console
.GetWidth(); // up to the end of line
462 for ( int i
= 1; i
<= iParam
[0]; i
++ )
463 Console
.WriteString(" ", 1);
464 Console
.SetRawCursorPosition(iKeepX
, iKeepY
);
467 // Go back p tab stops
468 // Added by I.Ioannou 06 April, 1997
469 // Implemented by Paul Brannan, 4/13/2000
472 int x
= Console
.GetCursorX();
473 for(int j
= 0; x
> 0 && j
< iParam
[0]; j
++)
474 while(x
> 0 && tab_stops
[j
] == tab_stops
[x
]) x
--;
475 Console
.SetCursorPosition(x
, Console
.GetCursorY());
481 const char* szTerminalId
= GetTerminalID();
482 Network
.WriteString(szTerminalId
, strlen(szTerminalId
));
485 // TITUS++ 2. November 1998: Repeat Character.
487 // isprint may be causing problems (Paul Brannan 3/27/99)
488 // if ( isprint(last_char) ) {
489 char buf
[150]; // at most 1 line (max 132 chars)
491 if ( iParam
[0] > 149 ) iParam
[0] = 149;
492 memset(buf
, last_char
, iParam
[0]);
495 Console
.WriteStringFast(buf
, iParam
[0]);
497 Console
.WriteString(buf
, iParam
[0]);
501 // Added by I.Ioannou 06 April, 1997
503 if (iCurrentParam
< 1) // Alter Default
505 // this was backward, and we should subtract 1 from y
506 // (Paul Brannan 5/27/98)
507 ConSetCursorPos(Console
.GetCursorX(), iParam
[0] - 1);
510 // Added by I.Ioannou 06 April, 1997
512 if (iCurrentParam
< 1) // Alter Default
517 // Clear the horizontal tab stop at the current active position
518 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++) {
519 int x
= Console
.GetCursorX();
520 if(tab_stops
[j
] == x
) tab_stops
[j
] = tab_stops
[x
+ 1];
525 // I think this might be "set as default?"
529 // Clear all tab stops
530 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++)
539 for (int i
= 0; i
< iCurrentParam
; i
++) {
540 // Changed to a switch statement (Paul Brannan 5/27/98)
541 if(flag
& FLAG_QMARK
) {
543 case 1: // App cursor keys
544 KeyTrans
.set_ext_mode(APP_KEY
);
546 case 2: // VT102 mode
548 KeyTrans
.unset_ext_mode(APP2_KEY
);
550 case 3: // 132 columns
551 if(ini
.get_wide_enable()) {
552 Console
.SetWindowSize(132, -1);
555 case 4: // smooth scrolling
557 case 5: // Light background
560 case 6: // Stay in margins
564 Console
.setLineWrap(true);
566 case 8: // Auto-repeat keys
568 case 18: // Send FF to printer
570 case 19: // Entire screen legal for printer
572 case 25: // Visible cursor
574 case 66: // Application numeric keypad
584 case 2: // Lock keyboard
586 case 3: // Act upon control codes (PB 12/5/98)
589 case 4: // Set insert mode
590 Console
.InsertMode(1);
592 case 12: // Local echo off
594 case 20: // Newline sends cr/lf
595 KeyTrans
.set_ext_mode(APP4_KEY
);
610 if (iCurrentParam
< 1)
613 case 0: break; // Print Screen
614 case 1: break; // Print Line
615 // Added I.Ioannou 06 April, 1997
619 if ( printfile
!= NULL
)
624 printfile
= fopen(ini
.get_printer_name(), "ab");
625 if (printfile
!= NULL
) InPrintMode
= 1;
629 // Unset extended mode
632 for (int i
= 0; i
< iCurrentParam
; i
++) {
633 // Changed to a switch statement (Paul Brannan 5/27/98)
634 if(flag
& FLAG_QMARK
) {
636 case 1: // Numeric cursor keys
637 KeyTrans
.unset_ext_mode(APP_KEY
);
641 KeyTrans
.set_ext_mode(APP2_KEY
);
643 case 3: // 80 columns
644 if(ini
.get_wide_enable()) {
645 Console
.SetWindowSize(80, -1);
648 case 4: // jump scrolling
650 case 5: // Dark background
653 case 6: // Ignore margins
657 Console
.setLineWrap(false);
659 case 8: // Auto-repeat keys
661 case 19: // Only send scrolling region to printer
663 case 25: // Invisible cursor
665 case 66: // Numeric keypad
675 case 2: // Unlock keyboard
677 case 3: // Display control codes (PB 12/5/98)
680 case 4: // Set overtype mode
681 Console
.InsertMode(0);
683 case 12: // Local echo on
685 case 20: // sends lf only
686 KeyTrans
.unset_ext_mode(APP4_KEY
);
687 newline_mode
= false;
701 if(missing_param
) Console
.Normal();
702 if(iCurrentParam
== 0) {
705 for(int i
= 0; i
< iCurrentParam
; i
++)
706 ConSetAttribute(iParam
[i
]);
709 // report cursor position Row X Col
711 if (iCurrentParam
== 1 && iParam
[0]==5) {
712 // report the cursor position
713 Network
.WriteString("\x1B[0n", 6);
716 if (iCurrentParam
== 1 && iParam
[0]==6){
717 // report the cursor position
718 // The cursor position needs to be sent as a single string
719 // (Paul Brannan 6/27/98)
720 char szCursorReport
[40] = "\x1B[";
722 itoa(Console
.GetCursorY() + 1,
723 &szCursorReport
[strlen(szCursorReport
)], 10);
724 strcat(szCursorReport
, ";");
725 itoa(Console
.GetCursorX() + 1,
726 &szCursorReport
[strlen(szCursorReport
)], 10);
727 strcat(szCursorReport
, "R");
729 Network
.WriteString(szCursorReport
, strlen(szCursorReport
));
733 // Miscellaneous weird sequences (Paul Brannan 6/27/98)
735 // Set conformance level
736 if(flag
& FLAG_QUOTE
) {
739 // Soft terminal reset
740 if(flag
& FLAG_EXCLAM
) {
743 // Report mode settings
744 if(flag
& FLAG_DOLLAR
) {
750 if (iCurrentParam
< 1) {
751 // Enable scrolling for entire display
752 Console
.SetScroll(-1, -1);
755 if (iCurrentParam
>1) {
756 // Enable scrolling from row1 to row2
757 Console
.SetScroll(iParam
[0] - 1, iParam
[1] - 1);
758 // If the cursor is outside the scrolling range, fix it
759 // (Paul Brannan 6/26/98)
760 // if(Console.GetRawCursorY() < iParam[0] - 1) {
761 // Console.SetRawCursorPosition(Console.GetCursorX(),
764 // if(Console.GetRawCursorY() > iParam[1] - 1) {
765 // Console.SetRawCursorPosition(Console.GetCursorX(),
769 // Move the cursor to the home position (Paul Brannan 12/2/98)
770 Console
.SetCursorPosition(0, 0);
772 // Save cursor position
774 SaveCurY(Console
.GetRawCursorY());
775 SaveCurX(Console
.GetRawCursorX());
777 // Restore cursor position
779 Console
.SetRawCursorPosition(iSavedCurX
, iSavedCurY
);
781 // DEC terminal report (Paul Brannan 6/28/98)
784 Network
.WriteString("\033[3;1;1;128;128;1;0x", 20);
786 Network
.WriteString("\033[2;1;1;128;128;1;0x", 20);
799 // Added by Frediano Ziglio, 5/31/2000
801 // initially copied from ParseEscapeANSI
802 char* TANSIParser::ParseEscapeMTE(char* pszBuffer
, char* pszBufferEnd
)
804 // The buffer contains something like <ESC>~pA
805 // where p is an optional decimal number specifying the count by which the
806 // appropriate action should take place.
807 // The pointer pszBuffer points us to the p, <ESC> and ~ are
808 // already 'consumed'
809 // TITUS: Simplification of the code: Assume default count of 1 in case
810 // there are no parameters.
812 const int nParam
= 10; // Maximum number of parameters
813 int iParam
[nParam
] = {1, 0, 0, 0, 0}; // Assume 1 parameter, Default 1
814 int iCurrentParam
= 0;
817 // Get parameters from escape sequence.
818 while ((tmpc
= *pszBuffer
) <= '?') {
819 if(tmpc
< '0' || tmpc
> '9') {
820 // Check for parameter delimiter.
828 // Got Numerical Parameter.
829 iParam
[iCurrentParam
] = strtoul(pszBuffer
, &pszBuffer
, 10);
830 if (iCurrentParam
< nParam
)
834 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
835 // So: If there is no digit, assume a count of 1
837 switch ((unsigned char)*pszBuffer
++) {
840 if (iCurrentParam
< 2 )
842 if (iParam
[0] <= 15 && iParam
[1] <= 15)
843 Console
.SetAttrib( (iParam
[1] << 4) | iParam
[0] );
849 if (iCurrentParam
< 2 )
851 mteRegionXF
= iParam
[1]-1;
852 mteRegionYF
= iParam
[0]-1;
858 if (mteRegionXF
== -1 || iCurrentParam
< 1)
860 sRepeat
[0] = (char)iParam
[0];
862 int xi
= Console
.GetCursorX(),yi
= Console
.GetCursorY();
863 int xf
= mteRegionXF
;
864 int yf
= mteRegionYF
;
866 for(int y
=yi
;y
<=yf
;++y
)
868 Console
.SetCursorPosition(xi
,y
);
869 for(int x
=xi
;x
<=xf
;++x
)
871 Console
.WriteStringFast(sRepeat
,1);
879 if (mteRegionXF
== -1 || iCurrentParam
< 2)
881 int /*x = Console.GetCursorX(),*/y
= Console
.GetCursorY();
882 // int xf = mteRegionXF;
883 int yf
= mteRegionYF
;
885 // !!! don't use x during scroll
886 int diff
= (iParam
[0]-1)-y
;
888 Console
.ScrollDown(y
-1,yf
,diff
);
890 Console
.ScrollDown(y
,yf
+1,diff
);
893 // Meridian main version ??
895 // disable echo and line mode
896 Network
.set_local_echo(0);
897 Network
.set_line_mode(0);
898 // Meridian Server handle cursor itself
899 Console
.SetCursorSize(0);
904 Network
.WriteString("\033vga.",5);
917 char* TANSIParser::ParseEscape(char* pszBuffer
, char* pszBufferEnd
) {
920 // Check if we have enough characters in buffer.
921 if ((pszBufferEnd
- pszBuffer
) < 2)
924 // I.Ioannou 04 Sep 1997
925 // there is no need for pszBuffer++; after each command
927 // Decode the command.
930 switch (*pszBuffer
++) {
931 case 'A': // Cursor up
932 Console
.MoveCursorPosition(0, -1);
936 Console
.MoveCursorPosition(0, 1);
940 Console
.MoveCursorPosition(1, 0);
942 // LF *or* cursor left (Paul Brannan 6/27/98)
945 Console
.MoveCursorPosition(-1, 0);
949 // CR/LF (Paul Brannan 6/26/98)
951 Console
.WriteCtrlString("\r\n", 2);
953 // Special graphics char set (Paul Brannan 6/27/98)
957 // ASCII char set (Paul Brannan 6/27/98)
961 // Home cursor/tab set
963 if(ini
.get_vt100_mode()) {
964 int x
= Console
.GetCursorX();
966 int t
= tab_stops
[x
- 1];
967 for(int j
= x
- 1; j
>= 0 && tab_stops
[j
] == t
; j
--)
971 // I.Ioannou 04 Sep 1997 (0,0) not (1,1)
972 ConSetCursorPos(0, 0);
975 // Reverse line feed (Paul Brannan 6/27/98)
976 // FIX ME!!! reverse_index is wrong to be calling here
977 // (Paul Brannan 12/2/98)
979 Console
.reverse_index();
981 // Erase end of screen
983 Console
.ClearEOScreen();
987 Console
.ClearEOLine();
989 // Scroll Up one line //Reverse index
991 Console
.reverse_index();
993 // Direct cursor addressing
995 if ((pszBufferEnd
- pszBuffer
) >= 2){
996 // if we subtract '\x1F', then we may end up with a negative
997 // cursor position! (Paul Brannan 6/26/98)
998 ConSetCursorPos(pszBuffer
[1] - ' ', pszBuffer
[0] - ' ');
1001 pszBuffer
--; // Paul Brannan 6/26/98
1004 // Terminal ID Request
1007 const char* szTerminalId
= GetTerminalID();
1008 Network
.WriteString(szTerminalId
, strlen(szTerminalId
));
1011 // reset terminal to defaults
1015 // Enter alternate keypad mode
1017 KeyTrans
.set_ext_mode(APP3_KEY
);
1019 // Exit alternate keypad mode
1021 KeyTrans
.unset_ext_mode(APP3_KEY
);
1025 KeyTrans
.unset_ext_mode(APP2_KEY
); // exit vt52 mode
1027 // Graphics processor on (See note 3)
1030 // Line size commands
1031 case '#': //Line size commands
1032 // (Paul Brannan 6/26/98)
1033 if(pszBuffer
< pszBufferEnd
) {
1034 switch(*pszBuffer
++) {
1035 case '3': break; // top half of a double-height line
1036 case '4': break; // bottom half of a double-height line
1037 case '6': break; // current line becomes double-width
1038 case '8': Console
.ClearScreen('E'); break;
1044 // Graphics processor off (See note 3)
1047 // Save cursor and attribs
1049 SaveCurY(Console
.GetRawCursorY());
1050 SaveCurX(Console
.GetRawCursorX());
1051 iSavedAttributes
= Console
.GetAttrib();
1053 // Restore cursor position and attribs
1055 Console
.SetRawCursorPosition(iSavedCurX
, iSavedCurY
);
1056 Console
.SetAttrib(iSavedAttributes
);
1058 // Set G0 map (Paul Brannan 6/25/98)
1060 if (pszBuffer
< pszBufferEnd
) {
1061 map_G0
= *pszBuffer
;
1062 if(current_map
== 0) Charmap
.setmap(map_G0
);
1068 // Set G1 map (Paul Brannan 6/25/98)
1070 if (pszBuffer
< pszBufferEnd
) {
1071 map_G1
= *pszBuffer
;
1072 if(current_map
== 1) Charmap
.setmap(map_G1
);
1078 // This doesn't do anything, as far as I can tell, but it does take
1079 // a parameter (Paul Brannan 6/27/98)
1081 if (pszBuffer
< pszBufferEnd
) {
1087 // ANSI escape sequence
1089 // Check if we have whole escape sequence in buffer.
1090 // This should not be isalpha anymore (Paul Brannan 9/1/98)
1091 pszChar
= pszBuffer
;
1092 while ((pszChar
< pszBufferEnd
) && (*pszChar
<= '?'))
1094 if (pszChar
== pszBufferEnd
)
1097 pszBuffer
= ParseEscapeANSI(pszBuffer
, pszBufferEnd
);
1101 // Frediano Ziglio, 5/31/2000
1102 // Meridian Terminal Emulator extension
1104 // !!! should put in MTE procedure
1105 pszChar
= pszBuffer
;
1106 while ((pszChar
< pszBufferEnd
) && (*pszChar
<= '?'))
1108 if (pszChar
== pszBufferEnd
)
1111 pszBuffer
= ParseEscapeMTE(pszBuffer
, pszBufferEnd
);
1124 // This function now only parses the ANSI buffer and does not do anything
1125 // with IAC sequences. That code has been moved to TTelHndl.cpp.
1126 // The scroller update routines have been moved to TScroll.cpp.
1127 // (Paul Brannan 6/15/98)
1128 char* TANSIParser::ParseBuffer(char* pszHead
, char* pszTail
){
1129 // copy into ANSI buffer
1132 // Parse the buffer for ANSI or display
1133 while (pszHead
< pszTail
) {
1134 if(!ini
.get_output_redir()) {
1135 pszResult
= ParseANSIBuffer(pszHead
, pszTail
);
1137 // Output is being redirected
1138 if(ini
.get_strip_redir()) {
1139 // Skip the WriteFile() altogether and pass the buffer to a filter
1140 // Mark Miesfield 09/24/2000
1141 pszResult
= PrintGoodChars(pszHead
, pszTail
);
1144 // Paul Brannan 7/29/98
1145 // Note that this has the unforunate effect of printing out
1146 // NULL (ascii 0) characters onto the screen
1147 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE
), pszHead
,
1148 pszTail
- pszHead
, &Result
, NULL
)) pszResult
= pszHead
;
1149 pszResult
= pszHead
+ Result
;
1153 fwrite( pszHead
, sizeof (char), pszResult
-pszHead
, dumpfile
);
1154 if(ini
.get_scroll_enable()) Scroller
.update(pszHead
, pszResult
);
1155 if (pszResult
== pszHead
) break;
1156 pszHead
= pszResult
;
1158 // return the new head to the buffer
1162 // A simple routine to strip ANSI sequences
1163 // This isn't perfect, but it does an okay job (Paul Brannan 7/5/98)
1164 // Fixed a line counting bug (Paul Brannan 12/4/98)
1165 int TANSIParser::StripBuffer(char* pszHead
, char* pszTail
, int width
) {
1166 int lines
= 0, c
= 0;
1167 char *pszBuf
= pszHead
;
1169 while(pszHead
< pszTail
) {
1170 if(iscntrl(*pszHead
)) {
1171 switch(*(pszHead
++)) {
1175 if(!(c
%width
)) lines
--;
1182 *(pszBuf
++) = *(pszHead
- 1);
1186 switch(*(pszHead
++)) {
1187 case 'Y': pszHead
+= 2; break;
1191 case '%': pszHead
++; break;
1193 while((pszHead
< pszTail
) && (*pszHead
< '?'))
1200 *(pszBuf
++) = *(pszHead
++);
1203 if(c
!= 0 && !(c
%width
))
1207 // Fill in the end of the buffer with blanks
1208 while(pszBuf
<= pszTail
) *pszBuf
++ = ' ';
1213 char* TANSIParser::ParseANSIBuffer(char* pszBuffer
, char* pszBufferEnd
)
1216 return PrintBuffer(pszBuffer
, pszBufferEnd
);
1219 unsigned char tmpc
= *(unsigned char *)pszBuffer
;
1222 return ParseEscape(pszBuffer
, pszBufferEnd
);
1225 // if((fast_write && tmpc < 32) ||
1226 // !print_ctrl && (tmpc < 32 || (EightBit_Ansi &&
1227 // (tmpc > 128 && tmpc < 128 + ' ')))) {
1229 // We shouldn't print ctrl characters when fast write is enabled
1230 // and ctrl chars are disabled (Paul Brannan 9/1/98)
1232 // From the Linux kernel (Paul Brannan 12/5/98):
1233 /* A bitmap for codes <32. A bit of 1 indicates that the code
1234 * corresponding to that bit number invokes some special action
1235 * (such as cursor movement) and should not be displayed as a
1236 * glyph unless the disp_ctrl mode is explicitly enabled.
1238 const long CTRL_ACTION
= 0x0d00ff81;
1239 const long CTRL_ALWAYS
= 0x0800f501;
1240 if(!(((print_ctrl
?CTRL_ALWAYS
:CTRL_ACTION
)>>tmpc
)&1)) {
1242 Console
.WriteString((char *)&tmpc
, 1);
1252 // I.Ioannou 5/30/98
1258 // destructive backspace
1260 // Added option for destructive backspace (Paul Brannan 5/13/98)
1261 // Changed to ConWriteCtrlString so that the cursor position can be
1262 // updated (Paul Brannan 5/25/98)
1263 if(ini
.get_dstrbksp()) {
1264 Console
.WriteCtrlChar('\b');
1265 Console
.WriteString(" ", 1);
1266 Console
.WriteCtrlChar('\b');
1268 else Console
.WriteCtrlChar('\b');
1276 int x
= Console
.GetCursorX();
1278 Console
.SetCursorPosition(tab_stops
[x
], Console
.GetCursorY());
1284 // Test for local echo (Paul Brannan 8/25/98)
1285 if(Network
.get_local_echo() || newline_mode
) // &&
1286 Console
.WriteCtrlChar('\x0d');
1287 Console
.WriteCtrlChar('\x0a');
1294 Console
.ClearScreen();
1295 Console
.SetRawCursorPosition(Console
.GetCursorX(), 1); // changed fm 1
1299 Console
.WriteCtrlChar('\x0d');
1304 case 14: // shift out of alternate chararcter set
1306 Charmap
.setmap(map_G1
); // Paul Brannan 6/25/98
1310 case 15: // shift in
1312 Charmap
.setmap(map_G0
); // Paul Brannan 6/25/98
1316 // Paul Brannan 9/1/98 - Is this okay?
1324 // added by I.Ioannou 06 April, 1997
1325 // In 8 bit systems the server may send 0x9b instead of ESC[
1326 // Well, this will produce troubles in Greek 737 Code page
1327 // which uses 0x9b as the small "delta" - and I thing that there
1328 // is another European country with the same problem.
1329 // If we have to stay 8-bit clean we may have to
1330 // give the ability of ROM characters (ESC[11m),
1331 // for striped 8'th bit (ESC[12m) as SCO does,
1332 // or a parameter at compile (or run ?) time.
1333 // We now check for a flag in the ini file (Paul Brannan 5/13/98)
1334 // We also handle any 8-bit ESC sequence (Paul Brannan 6/28/98)
1335 if(ini
.get_eightbit_ansi() && (tmpc
> 128 && tmpc
< 128 + ' ')) {
1336 // There's a chance the sequence might not parse. If this happens
1337 // then pszBuffer will be one character too far back, since
1338 // ParseEscape is expecting two characters, not one.
1339 // In that case we must handle it.
1340 char *pszCurrent
= pszBuffer
;
1341 pszBuffer
= ParseEscape(pszBuffer
, pszBufferEnd
);
1342 if(pszBuffer
< pszCurrent
) pszBuffer
= pszCurrent
;
1345 char* pszCurrent
= pszBuffer
+ 1;
1346 // I.Ioannou 04 Sep 1997 FIXME with ESC[11m must show chars < 32
1347 // Fixed (Paul Brannan 6/28/98)
1348 while ((pszCurrent
< pszBufferEnd
) && (!iscntrl(*pszCurrent
))) {
1349 // I.Ioannou 04 Sep 1997 strip on high bit
1350 if ( (inGraphMode
) && (*pszCurrent
> (char)32) )
1351 *pszCurrent
|= 0x80 ;
1355 // Note that this may break dumpfiles slightly.
1356 // If 'B' is set to anything other than ASCII, this will cause problems
1357 // (Paul Brannan 6/28/98)
1358 if(current_map
!= 'B' && Charmap
.enabled
)
1359 Charmap
.translate_buffer(pszBuffer
, pszCurrent
);
1361 last_char
= *(pszCurrent
-1); // TITUS++: Remember last char
1364 pszBuffer
+= Console
.WriteStringFast(pszBuffer
,
1365 pszCurrent
- pszBuffer
);
1367 pszBuffer
+= Console
.WriteString(pszBuffer
,
1368 pszCurrent
- pszBuffer
);
1374 // Added by I.Ioannou 06 April, 1997
1375 // Print the buffer until you reach ESC[4i
1376 char* TANSIParser::PrintBuffer(char* pszBuffer
, char* pszBufferEnd
) {
1377 // Check if we have enough characters in buffer.
1378 if ((pszBufferEnd
- pszBuffer
) < 4)
1382 tmpChar
= pszBuffer
;
1383 if ( *tmpChar
== 27 ) {
1385 if ( *tmpChar
== '[' ) {
1387 if ( *tmpChar
== '4' ) {
1389 if ( *tmpChar
== 'i' ) {
1390 InPrintMode
= 0; // Stop Print Log
1391 if ( printfile
!= NULL
)
1400 if (printfile
!= NULL
) {
1401 fputc( *pszBuffer
, printfile
);
1409 /* - PrintGoodChars( pszHead, pszTail ) - - - - - - - - - - - - - - - - - - -
1412 Mark Miesfield 09/24/2000
1414 Prints the characters in a buffer, from the specified head to the specified
1415 tail, to standard out, skipping any control characters or ANSI escape
1418 Parameters on entry:
1419 pszHead -> Starting point in buffer.
1421 pszTail -> Ending point in buffer.
1424 Pointer to the first character in the buffer that was not output to
1425 standard out. (Since no error checking is done, this is in effect
1430 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1432 char * TANSIParser::PrintGoodChars( char * pszHead
, char * pszTail
) {
1434 while ( pszHead
< pszTail
) {
1435 if ( iscntrl( *pszHead
) ) {
1436 switch ( *(pszHead
++) ) {
1446 switch ( *(pszHead
++) ) {
1454 case '%': pszHead
++; break;
1456 while ( (pszHead
< pszTail
) && (*pszHead
< '?') )
1471 putc( *(pszHead
++), stdout
);
1475 // End of function: PrintGoodChars( pszHead, pszTail )