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 ///////////////////////////////////////////////////////////////////////////////
56 // The constructor now takes different arguments and initializes different
57 // variables (Paul Brannan 6/15/98)
58 TANSIParser::TANSIParser(TConsole
&RefConsole
, KeyTranslator
&RefKeyTrans
,
59 TScroller
&RefScroller
, TNetwork
&RefNetwork
,
60 TCharmap
&RefCharmap
):
61 TParser(RefConsole
, RefKeyTrans
, RefScroller
, RefNetwork
, RefCharmap
) {
63 iSavedAttributes
= (unsigned char) 7;
64 // must also check to make sure the string is non-NULL
65 // (Paul Brannan 5/8/98)
66 if ((ini
.get_dumpfile() != NULL
) && (*ini
.get_dumpfile() != '\0')){
67 dumpfile
= fopen(ini
.get_dumpfile(), "wb");
74 fast_write
= ini
.get_fast_write(); // Paul Brannan 6/28/98
75 Scroller
.init(&StripBuffer
);
78 TANSIParser::~TANSIParser(){
79 if (dumpfile
) fclose (dumpfile
);
80 // Added I.Ioannou 06 April, 1997
81 if (printfile
!= NULL
) fclose (printfile
);
84 // Created Init() function to initialize the parser but not clear the screen
85 // (Paul Brannan 9/23/98)
86 void TANSIParser::Init() {
87 // Paul Brannan 6/25/98
88 map_G0
= 'B'; map_G1
= 'B';
89 Charmap
.setmap(map_G0
);
97 KeyTrans
.clear_ext_mode();
99 iSavedCurY
= 0; // Reset Variables
102 Console
.SetScroll(-1, -1);
103 Console
.Normal(); // Reset Attributes
109 void TANSIParser::ResetTerminal() {
111 Console
.ClearScreen(); // Clear Screen
112 Console
.SetRawCursorPosition(0,0); // Home Cursor
114 void TANSIParser::SaveCurY(int iY
){
118 void TANSIParser::SaveCurX(int iX
){
122 void TANSIParser::resetTabStops() {
123 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++) {
124 tab_stops
[j
] = 8 + j
- (j
%8);
128 void TANSIParser::ConSetAttribute(unsigned char TextAttrib
){
129 // Paul Brannan 5/8/98
130 // Made this go a little bit faster by changing from switch{} to an array
132 if(TextAttrib
>= 30) {
133 if(TextAttrib
<= 37) {
134 Console
.SetForeground(ANSIColors
[TextAttrib
-30]);
136 } else if((TextAttrib
>= 40) && (TextAttrib
<= 47)) {
137 Console
.SetBackground(ANSIColors
[TextAttrib
-40]);
144 case 0: Console
.Normal(); break; // Normal video
145 case 1: Console
.HighVideo(); break; // High video
146 case 2: Console
.LowVideo(); break; // Low video
147 case 4: Console
.UnderlineOn(); break; // Underline on (I.Ioannou)
148 case 5: Console
.BlinkOn(); break; // Blink video
149 // Corrected by I.Ioannou 11 May, 1997
150 case 7: Console
.ReverseOn(); break; // Reverse video
151 case 8: break; // hidden
152 // All from 10 thru 27 are hacked from linux kernel
153 // I.Ioannou 06 April, 1997
155 // I.Ioannou 04 Sep 1997 turn on/off high bit
158 Charmap
.setmap(current_map
? map_G1
:map_G0
); // Paul Brannan 6/25/98
159 break; // ANSI X3.64-1979 (SCO-ish?)
160 // Select primary font,
161 // don't display control chars
162 // if defined, don't set
163 // bit 8 on output (normal)
167 Charmap
.setmap(0); // Paul Brannan 6/25/98
168 break; // ANSI X3.64-1979 (SCO-ish?)
169 // Select first alternate font,
170 // let chars < 32 be displayed
175 Charmap
.setmap(0); // Paul Brannan 6/25/98
176 break; // ANSI X3.64-1979 (SCO-ish?)
177 // Select second alternate font,
178 // toggle high bit before
179 // displaying as ROM char.
181 case 21: // not really Low video
182 case 22: Console
.LowVideo(); break; // but this works good also
183 case 24: Console
.UnderlineOff(); break; // Underline off
184 case 25: Console
.BlinkOff(); break; // blink off
185 // Corrected by I.Ioannou 11 May, 1997
186 case 27: Console
.ReverseOff(); break; //Reverse video off
188 // Mutt needs this (Paul Brannan, Peter Jordan 12/31/98)
189 // This is from the Linux kernel source
190 case 38: /* ANSI X3.64-1979 (SCO-ish?)
191 * Enables underscore, white foreground
192 * with white underscore (Linux - use
193 * default foreground).
195 Console
.UnderlineOn();
196 Console
.SetForeground(ini
.get_normal_fg());
198 case 39: /* ANSI X3.64-1979 (SCO-ish?)
199 * Disable underline option.
200 * Reset colour to default? It did this
203 Console
.UnderlineOff();
204 Console
.SetForeground(ini
.get_normal_fg());
207 Console
.SetBackground(ini
.get_normal_bg());
213 void TANSIParser::ConSetCursorPos(int x
, int y
) {
215 Console
.SetRawCursorPosition(x
, y
);
217 Console
.SetCursorPosition(x
, y
);
220 char* TANSIParser::GetTerminalID()
225 // All of the Telnet protocol stuff has been moved to TTelHndl.cpp
226 // This is more consistent with what OO should be
227 // (Paul Brannan 6/15/98)
230 // argsused doesn't work on MSVC++
234 // Use this for the VT100 flags (Paul Brannan 12/2/98)
235 #define FLAG_DOLLAR 0x0001
236 #define FLAG_QMARK 0x0002
237 #define FLAG_GREATER 0x0004
238 #define FLAG_LESS 0x0008
239 #define FLAG_EXCLAM 0x0010
240 #define FLAG_AMPERSAND 0x0020
241 #define FLAG_SLASH 0x0040
242 #define FLAG_EQUAL 0x0080
243 #define FLAG_QUOTE 0x0100
244 #define FLAG_OTHER 0x8000
246 char* TANSIParser::ParseEscapeANSI(char* pszBuffer
, char* pszBufferEnd
)
249 // The buffer contains something like <ESC>[pA
250 // where p is an optional decimal number specifying the count by which the
251 // appropriate action should take place.
252 // The pointer pszBuffer points us to the p, <ESC> and [ are
253 // already 'consumed'
255 // TITUS: Simplification of the code: Assume default count of 1 in case
256 // there are no parameters.
258 const int nParam
= 10; // Maximum number of parameters
259 int iParam
[nParam
] = {1, 0, 0, 0, 0}; // Assume 1 Parameter, Default 1
260 int iCurrentParam
= 0;
262 int missing_param
= 0;
264 // Get parameters from escape sequence.
265 while ((tmpc
= *pszBuffer
) <= '?') {
267 if(tmpc
< '0' || tmpc
> '9') {
268 // Check for parameter delimiter.
270 // This is a hack (Paul Brannan 6/27/98)
271 if(*(pszBuffer
- 1) == '[') missing_param
= iCurrentParam
+1;
276 // It is legal to have control characters inside ANSI sequences
277 // (Paul Brannan 6/26/98)
279 Console
.WriteCtrlChar(tmpc
);
284 // A new way of handling flags (Paul Brannan 12/2/98)
286 case '$': flag
|= FLAG_DOLLAR
; break;
287 case '?': flag
|= FLAG_QMARK
; break;
288 case '>': flag
|= FLAG_GREATER
; break;
289 case '<': flag
|= FLAG_LESS
; break;
290 case '!': flag
|= FLAG_EXCLAM
; break;
291 case '&': flag
|= FLAG_AMPERSAND
; break;
292 case '/': flag
|= FLAG_SLASH
; break;
293 case '=': flag
|= FLAG_EQUAL
; break;
294 case '\"': flag
|= FLAG_QUOTE
; break;
295 default: flag
|= FLAG_OTHER
; break;
301 // Got Numerical Parameter.
302 iParam
[iCurrentParam
] = strtoul(pszBuffer
, &pszBuffer
, 10);
303 if (iCurrentParam
< nParam
)
307 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
308 // So: If there is no digit, assume a count of 1
310 switch ((unsigned char)*pszBuffer
++) {
313 if(iParam
[0] == 0) iParam
[0] = 1; // Paul Brannan 9/1/98
314 Console
.InsertCharacter(iParam
[0]); break;
317 if(iParam
[0] == 0) iParam
[0] = 1;
318 Console
.MoveCursorPosition(0, -iParam
[0]); break;
320 // Added by I.Ioannou 06 April, 1997
323 if(iParam
[0] == 0) iParam
[0] = 1;
324 Console
.MoveCursorPosition(0, iParam
[0]);
326 // Move cursor right.
327 // Added by I.Ioannou 06 April, 1997
330 // Handle cursor size sequences (Jose Cesar Otero Rodriquez and
331 // Paul Brannan, 3/27/1999)
332 if(flag
& FLAG_EQUAL
) {
334 case 7: Console
.SetCursorSize(50); break;
335 case 11: Console
.SetCursorSize(6); break;
336 case 32: Console
.SetCursorSize(0); break;
337 default: Console
.SetCursorSize(13);
340 if(iParam
[0] == 0) iParam
[0] = 1;
341 Console
.MoveCursorPosition(iParam
[0], 0);
346 if(iParam
[0] == 0) iParam
[0] = 1;
347 Console
.MoveCursorPosition(-iParam
[0], 0);
349 // Move cursor to beginning of line, p lines down.
350 // Added by I.Ioannou 06 April, 1997
352 Console
.MoveCursorPosition(-Console
.GetCursorX(), iParam
[0]);
354 // Moves active position to beginning of line, p lines up
355 // Added by I.Ioannou 06 April, 1997
356 // With '=' this changes the default fg color (Paul Brannan 6/27/98)
358 if(flag
& FLAG_EQUAL
)
359 Console
.setDefaultFg(iParam
[0]);
361 Console
.MoveCursorPosition(-Console
.GetCursorX(), -iParam
[0]);
364 // Added by I.Ioannou 06 April, 1997
365 // With '=' this changes the default bg color (Paul Brannan 6/27/98)
367 case 'G': // 'G' is from Linux kernel sources
368 if(flag
& FLAG_EQUAL
) {
369 Console
.setDefaultBg(iParam
[0]);
371 if (iCurrentParam
< 1) // Alter Default
373 // this was backward, and we should subtract 1 from x
374 // (Paul Brannan 5/27/98)
375 ConSetCursorPos(iParam
[0] - 1, Console
.GetCursorY());
378 // Set cursor position.
381 if (iCurrentParam
< 2 || iParam
[1] < 1)
383 ConSetCursorPos(iParam
[1] - 1, iParam
[0] - 1);
387 if ( iCurrentParam
< 1 ) iParam
[0] = 0; // Alter Default
389 case 0: Console
.ClearEOScreen(); break;
390 case 1: Console
.ClearBOScreen(); break;
392 Console
.ClearScreen();
393 Console
.SetRawCursorPosition(0, 0);
399 if (iCurrentParam
< 1) // Alter Default
402 case 0: Console
.ClearEOLine(); break;
403 case 1: Console
.ClearBOLine(); break;
404 case 2: Console
.ClearLine(); break;
407 // Insert p new, blank lines.
408 // Added by I.Ioannou 06 April, 1997
411 // for (int i = 1; i <= iParam[0]; i++)
412 // This should speed things up a bit (Paul Brannan 9/2/98)
413 Console
.ScrollDown(Console
.GetRawCursorY(), -1, iParam
[0]);
417 // Added by I.Ioannou 06 April, 1997
420 for (int i
= 1; i
<= iParam
[0]; i
++)
421 // This should speed things up a bit (Paul Brannan 9/2/98)
422 Console
.ScrollDown(Console
.GetRawCursorY(), -1, -1);
427 Console
.DeleteCharacter(iParam
[0]);
429 // Scrolls screen up (down? -- PB) p lines,
430 // Added by I.Ioannou 06 April, 1997
431 // ANSI X3.64-1979 references this but I didn't
432 // found it in any telnet implementation
433 // note 05 Oct 97 : but SCO terminfo uses them, so uncomment them !!
436 //for (int i = 1; i <= iParam[0]; i++)
437 // This should speed things up a bit (Paul Brannan 9/2/98)
438 Console
.ScrollDown(-1, -1, -iParam
[0]);
441 // Scrolls screen up p lines,
442 // Added by I.Ioannou 06 April, 1997
443 // ANSI X3.64-1979 references this but I didn't
444 // found it in any telnet implementation
445 // note 05 Oct 97 : but SCO terminfo uses them, so uncomment them !!
448 // for (int i = 1; i <= iParam[0]; i++)
449 // This should speed things up a bit (Paul Brannan 9/2/98)
450 Console
.ScrollDown(-1, -1, iParam
[0]);
453 // Erases p characters up to the end of line
454 // Added by I.Ioannou 06 April, 1997
457 int iKeepX
= Console
.GetRawCursorX();
458 int iKeepY
= Console
.GetRawCursorY();
459 if (iParam
[0] > Console
.GetWidth())
460 iParam
[0] = Console
.GetWidth(); // up to the end of line
461 for ( int i
= 1; i
<= iParam
[0]; i
++ )
462 Console
.WriteString(" ", 1);
463 Console
.SetRawCursorPosition(iKeepX
, iKeepY
);
466 // Go back p tab stops
467 // Added by I.Ioannou 06 April, 1997
468 // Implemented by Paul Brannan, 4/13/2000
471 int x
= Console
.GetCursorX();
472 for(int j
= 0; x
> 0 && j
< iParam
[0]; j
++)
473 while(x
> 0 && tab_stops
[j
] == tab_stops
[x
]) x
--;
474 Console
.SetCursorPosition(x
, Console
.GetCursorY());
480 char* szTerminalId
= GetTerminalID();
481 Network
.WriteString(szTerminalId
, strlen(szTerminalId
));
484 // TITUS++ 2. November 1998: Repeat Character.
486 // isprint may be causing problems (Paul Brannan 3/27/99)
487 // if ( isprint(last_char) ) {
488 char buf
[150]; // at most 1 line (max 132 chars)
490 if ( iParam
[0] > 149 ) iParam
[0] = 149;
491 memset(buf
, last_char
, iParam
[0]);
494 Console
.WriteStringFast(buf
, iParam
[0]);
496 Console
.WriteString(buf
, iParam
[0]);
500 // Added by I.Ioannou 06 April, 1997
502 if (iCurrentParam
< 1) // Alter Default
504 // this was backward, and we should subtract 1 from y
505 // (Paul Brannan 5/27/98)
506 ConSetCursorPos(Console
.GetCursorX(), iParam
[0] - 1);
509 // Added by I.Ioannou 06 April, 1997
511 if (iCurrentParam
< 1) // Alter Default
516 // Clear the horizontal tab stop at the current active position
517 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++) {
518 int x
= Console
.GetCursorX();
519 if(tab_stops
[j
] == x
) tab_stops
[j
] = tab_stops
[x
+ 1];
524 // I think this might be "set as default?"
528 // Clear all tab stops
529 for(int j
= 0; j
< MAX_TAB_POSITIONS
; j
++)
538 for (int i
= 0; i
< iCurrentParam
; i
++) {
539 // Changed to a switch statement (Paul Brannan 5/27/98)
540 if(flag
& FLAG_QMARK
) {
542 case 1: // App cursor keys
543 KeyTrans
.set_ext_mode(APP_KEY
);
545 case 2: // VT102 mode
547 KeyTrans
.unset_ext_mode(APP2_KEY
);
549 case 3: // 132 columns
550 if(ini
.get_wide_enable()) {
551 Console
.SetWindowSize(132, -1);
554 case 4: // smooth scrolling
556 case 5: // Light background
559 case 6: // Stay in margins
563 Console
.setLineWrap(true);
565 case 8: // Auto-repeat keys
567 case 18: // Send FF to printer
569 case 19: // Entire screen legal for printer
571 case 25: // Visible cursor
573 case 66: // Application numeric keypad
583 case 2: // Lock keyboard
585 case 3: // Act upon control codes (PB 12/5/98)
588 case 4: // Set insert mode
589 Console
.InsertMode(1);
591 case 12: // Local echo off
593 case 20: // Newline sends cr/lf
594 KeyTrans
.set_ext_mode(APP4_KEY
);
609 if (iCurrentParam
< 1)
612 case 0: break; // Print Screen
613 case 1: break; // Print Line
614 // Added I.Ioannou 06 April, 1997
618 if ( printfile
!= NULL
)
623 printfile
= fopen(ini
.get_printer_name(), "ab");
624 if (printfile
!= NULL
) InPrintMode
= 1;
628 // Unset extended mode
631 for (int i
= 0; i
< iCurrentParam
; i
++) {
632 // Changed to a switch statement (Paul Brannan 5/27/98)
633 if(flag
& FLAG_QMARK
) {
635 case 1: // Numeric cursor keys
636 KeyTrans
.unset_ext_mode(APP_KEY
);
640 KeyTrans
.set_ext_mode(APP2_KEY
);
642 case 3: // 80 columns
643 if(ini
.get_wide_enable()) {
644 Console
.SetWindowSize(80, -1);
647 case 4: // jump scrolling
649 case 5: // Dark background
652 case 6: // Ignore margins
656 Console
.setLineWrap(false);
658 case 8: // Auto-repeat keys
660 case 19: // Only send scrolling region to printer
662 case 25: // Invisible cursor
664 case 66: // Numeric keypad
674 case 2: // Unlock keyboard
676 case 3: // Display control codes (PB 12/5/98)
679 case 4: // Set overtype mode
680 Console
.InsertMode(0);
682 case 12: // Local echo on
684 case 20: // sends lf only
685 KeyTrans
.unset_ext_mode(APP4_KEY
);
686 newline_mode
= false;
700 if(missing_param
) Console
.Normal();
701 if(iCurrentParam
== 0) {
704 for(int i
= 0; i
< iCurrentParam
; i
++)
705 ConSetAttribute(iParam
[i
]);
708 // report cursor position Row X Col
710 if (iCurrentParam
== 1 && iParam
[0]==5) {
711 // report the cursor position
712 Network
.WriteString("\x1B[0n", 6);
715 if (iCurrentParam
== 1 && iParam
[0]==6){
716 // report the cursor position
717 // The cursor position needs to be sent as a single string
718 // (Paul Brannan 6/27/98)
719 char szCursorReport
[40] = "\x1B[";
721 itoa(Console
.GetCursorY() + 1,
722 &szCursorReport
[strlen(szCursorReport
)], 10);
723 strcat(szCursorReport
, ";");
724 itoa(Console
.GetCursorX() + 1,
725 &szCursorReport
[strlen(szCursorReport
)], 10);
726 strcat(szCursorReport
, "R");
728 Network
.WriteString(szCursorReport
, strlen(szCursorReport
));
732 // Miscellaneous weird sequences (Paul Brannan 6/27/98)
734 // Set conformance level
735 if(flag
& FLAG_QUOTE
) {
738 // Soft terminal reset
739 if(flag
& FLAG_EXCLAM
) {
742 // Report mode settings
743 if(flag
& FLAG_DOLLAR
) {
749 if (iCurrentParam
< 1) {
750 // Enable scrolling for entire display
751 Console
.SetScroll(-1, -1);
754 if (iCurrentParam
>1) {
755 // Enable scrolling from row1 to row2
756 Console
.SetScroll(iParam
[0] - 1, iParam
[1] - 1);
757 // If the cursor is outside the scrolling range, fix it
758 // (Paul Brannan 6/26/98)
759 // if(Console.GetRawCursorY() < iParam[0] - 1) {
760 // Console.SetRawCursorPosition(Console.GetCursorX(),
763 // if(Console.GetRawCursorY() > iParam[1] - 1) {
764 // Console.SetRawCursorPosition(Console.GetCursorX(),
768 // Move the cursor to the home position (Paul Brannan 12/2/98)
769 Console
.SetCursorPosition(0, 0);
771 // Save cursor position
773 SaveCurY(Console
.GetRawCursorY());
774 SaveCurX(Console
.GetRawCursorX());
776 // Restore cursor position
778 Console
.SetRawCursorPosition(iSavedCurX
, iSavedCurY
);
780 // DEC terminal report (Paul Brannan 6/28/98)
783 Network
.WriteString("\033[3;1;1;128;128;1;0x", 20);
785 Network
.WriteString("\033[2;1;1;128;128;1;0x", 20);
798 // Added by Frediano Ziglio, 5/31/2000
800 // initially copied from ParseEscapeANSI
801 char* TANSIParser::ParseEscapeMTE(char* pszBuffer
, char* pszBufferEnd
)
803 // The buffer contains something like <ESC>~pA
804 // where p is an optional decimal number specifying the count by which the
805 // appropriate action should take place.
806 // The pointer pszBuffer points us to the p, <ESC> and ~ are
807 // already 'consumed'
808 // TITUS: Simplification of the code: Assume default count of 1 in case
809 // there are no parameters.
811 const int nParam
= 10; // Maximum number of parameters
812 int iParam
[nParam
] = {1, 0, 0, 0, 0}; // Assume 1 parameter, Default 1
813 int iCurrentParam
= 0;
816 // Get parameters from escape sequence.
817 while ((tmpc
= *pszBuffer
) <= '?') {
818 if(tmpc
< '0' || tmpc
> '9') {
819 // Check for parameter delimiter.
827 // Got Numerical Parameter.
828 iParam
[iCurrentParam
] = strtoul(pszBuffer
, &pszBuffer
, 10);
829 if (iCurrentParam
< nParam
)
833 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
834 // So: If there is no digit, assume a count of 1
836 switch ((unsigned char)*pszBuffer
++) {
839 if (iCurrentParam
< 2 )
841 if (iParam
[0] <= 15 && iParam
[1] <= 15)
842 Console
.SetAttrib( (iParam
[1] << 4) | iParam
[0] );
848 if (iCurrentParam
< 2 )
850 mteRegionXF
= iParam
[1]-1;
851 mteRegionYF
= iParam
[0]-1;
857 if (mteRegionXF
== -1 || iCurrentParam
< 1)
859 sRepeat
[0] = (char)iParam
[0];
861 int xi
= Console
.GetCursorX(),yi
= Console
.GetCursorY();
862 int xf
= mteRegionXF
;
863 int yf
= mteRegionYF
;
865 for(int y
=yi
;y
<=yf
;++y
)
867 Console
.SetCursorPosition(xi
,y
);
868 for(int x
=xi
;x
<=xf
;++x
)
870 Console
.WriteStringFast(sRepeat
,1);
878 if (mteRegionXF
== -1 || iCurrentParam
< 2)
880 int /*x = Console.GetCursorX(),*/y
= Console
.GetCursorY();
881 // int xf = mteRegionXF;
882 int yf
= mteRegionYF
;
884 // !!! don't use x during scroll
885 int diff
= (iParam
[0]-1)-y
;
887 Console
.ScrollDown(y
-1,yf
,diff
);
889 Console
.ScrollDown(y
,yf
+1,diff
);
892 // Meridian main version ??
894 // disable echo and line mode
895 Network
.set_local_echo(0);
896 Network
.set_line_mode(0);
897 // Meridian Server handle cursor itself
898 Console
.SetCursorSize(0);
903 Network
.WriteString("\033vga.",5);
916 char* TANSIParser::ParseEscape(char* pszBuffer
, char* pszBufferEnd
) {
919 // Check if we have enough characters in buffer.
920 if ((pszBufferEnd
- pszBuffer
) < 2)
923 // I.Ioannou 04 Sep 1997
924 // there is no need for pszBuffer++; after each command
926 // Decode the command.
929 switch (*pszBuffer
++) {
930 case 'A': // Cursor up
931 Console
.MoveCursorPosition(0, -1);
935 Console
.MoveCursorPosition(0, 1);
939 Console
.MoveCursorPosition(1, 0);
941 // LF *or* cursor left (Paul Brannan 6/27/98)
944 Console
.MoveCursorPosition(-1, 0);
948 // CR/LF (Paul Brannan 6/26/98)
950 Console
.WriteCtrlString("\r\n", 2);
952 // Special graphics char set (Paul Brannan 6/27/98)
956 // ASCII char set (Paul Brannan 6/27/98)
960 // Home cursor/tab set
962 if(ini
.get_vt100_mode()) {
963 int x
= Console
.GetCursorX();
965 int t
= tab_stops
[x
- 1];
966 for(int j
= x
- 1; j
>= 0 && tab_stops
[j
] == t
; j
--)
970 // I.Ioannou 04 Sep 1997 (0,0) not (1,1)
971 ConSetCursorPos(0, 0);
974 // Reverse line feed (Paul Brannan 6/27/98)
975 // FIX ME!!! reverse_index is wrong to be calling here
976 // (Paul Brannan 12/2/98)
978 Console
.reverse_index();
980 // Erase end of screen
982 Console
.ClearEOScreen();
986 Console
.ClearEOLine();
988 // Scroll Up one line //Reverse index
990 Console
.reverse_index();
992 // Direct cursor addressing
994 if ((pszBufferEnd
- pszBuffer
) >= 2){
995 // if we subtract '\x1F', then we may end up with a negative
996 // cursor position! (Paul Brannan 6/26/98)
997 ConSetCursorPos(pszBuffer
[1] - ' ', pszBuffer
[0] - ' ');
1000 pszBuffer
--; // Paul Brannan 6/26/98
1003 // Terminal ID Request
1006 char* szTerminalId
= GetTerminalID();
1007 Network
.WriteString(szTerminalId
, strlen(szTerminalId
));
1010 // reset terminal to defaults
1014 // Enter alternate keypad mode
1016 KeyTrans
.set_ext_mode(APP3_KEY
);
1018 // Exit alternate keypad mode
1020 KeyTrans
.unset_ext_mode(APP3_KEY
);
1024 KeyTrans
.unset_ext_mode(APP2_KEY
); // exit vt52 mode
1026 // Graphics processor on (See note 3)
1029 // Line size commands
1030 case '#': //Line size commands
1031 // (Paul Brannan 6/26/98)
1032 if(pszBuffer
< pszBufferEnd
) {
1033 switch(*pszBuffer
++) {
1034 case '3': break; // top half of a double-height line
1035 case '4': break; // bottom half of a double-height line
1036 case '6': break; // current line becomes double-width
1037 case '8': Console
.ClearScreen('E'); break;
1043 // Graphics processor off (See note 3)
1046 // Save cursor and attribs
1048 SaveCurY(Console
.GetRawCursorY());
1049 SaveCurX(Console
.GetRawCursorX());
1050 iSavedAttributes
= Console
.GetAttrib();
1052 // Restore cursor position and attribs
1054 Console
.SetRawCursorPosition(iSavedCurX
, iSavedCurY
);
1055 Console
.SetAttrib(iSavedAttributes
);
1057 // Set G0 map (Paul Brannan 6/25/98)
1059 if (pszBuffer
< pszBufferEnd
) {
1060 map_G0
= *pszBuffer
;
1061 if(current_map
== 0) Charmap
.setmap(map_G0
);
1067 // Set G1 map (Paul Brannan 6/25/98)
1069 if (pszBuffer
< pszBufferEnd
) {
1070 map_G1
= *pszBuffer
;
1071 if(current_map
== 1) Charmap
.setmap(map_G1
);
1077 // This doesn't do anything, as far as I can tell, but it does take
1078 // a parameter (Paul Brannan 6/27/98)
1080 if (pszBuffer
< pszBufferEnd
) {
1086 // ANSI escape sequence
1088 // Check if we have whole escape sequence in buffer.
1089 // This should not be isalpha anymore (Paul Brannan 9/1/98)
1090 pszChar
= pszBuffer
;
1091 while ((pszChar
< pszBufferEnd
) && (*pszChar
<= '?'))
1093 if (pszChar
== pszBufferEnd
)
1096 pszBuffer
= ParseEscapeANSI(pszBuffer
, pszBufferEnd
);
1100 // Frediano Ziglio, 5/31/2000
1101 // Meridian Terminal Emulator extension
1103 // !!! should put in MTE procedure
1104 pszChar
= pszBuffer
;
1105 while ((pszChar
< pszBufferEnd
) && (*pszChar
<= '?'))
1107 if (pszChar
== pszBufferEnd
)
1110 pszBuffer
= ParseEscapeMTE(pszBuffer
, pszBufferEnd
);
1123 // This function now only parses the ANSI buffer and does not do anything
1124 // with IAC sequences. That code has been moved to TTelHndl.cpp.
1125 // The scroller update routines have been moved to TScroll.cpp.
1126 // (Paul Brannan 6/15/98)
1127 char* TANSIParser::ParseBuffer(char* pszHead
, char* pszTail
){
1128 // copy into ANSI buffer
1131 // Parse the buffer for ANSI or display
1132 while (pszHead
< pszTail
) {
1133 if(!ini
.get_output_redir()) {
1134 pszResult
= ParseANSIBuffer(pszHead
, pszTail
);
1136 // Output is being redirected
1137 if(ini
.get_strip_redir()) {
1138 // Skip the WriteFile() altogether and pass the buffer to a filter
1139 // Mark Miesfield 09/24/2000
1140 pszResult
= PrintGoodChars(pszHead
, pszTail
);
1143 // Paul Brannan 7/29/98
1144 // Note that this has the unforunate effect of printing out
1145 // NULL (ascii 0) characters onto the screen
1146 if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE
), pszHead
,
1147 pszTail
- pszHead
, &Result
, NULL
)) pszResult
= pszHead
;
1148 pszResult
= pszHead
+ Result
;
1152 fwrite( pszHead
, sizeof (char), pszResult
-pszHead
, dumpfile
);
1153 if(ini
.get_scroll_enable()) Scroller
.update(pszHead
, pszResult
);
1154 if (pszResult
== pszHead
) break;
1155 pszHead
= pszResult
;
1157 // return the new head to the buffer
1161 // A simple routine to strip ANSI sequences
1162 // This isn't perfect, but it does an okay job (Paul Brannan 7/5/98)
1163 // Fixed a line counting bug (Paul Brannan 12/4/98)
1164 int TANSIParser::StripBuffer(char* pszHead
, char* pszTail
, int width
) {
1165 int lines
= 0, c
= 0;
1166 char *pszBuf
= pszHead
;
1168 while(pszHead
< pszTail
) {
1169 if(iscntrl(*pszHead
)) {
1170 switch(*(pszHead
++)) {
1174 if(!(c
%width
)) lines
--;
1181 *(pszBuf
++) = *(pszHead
- 1);
1185 switch(*(pszHead
++)) {
1186 case 'Y': pszHead
+= 2; break;
1190 case '%': pszHead
++; break;
1192 while((pszHead
< pszTail
) && (*pszHead
< '?'))
1199 *(pszBuf
++) = *(pszHead
++);
1202 if(c
!= 0 && !(c
%width
))
1206 // Fill in the end of the buffer with blanks
1207 while(pszBuf
<= pszTail
) *pszBuf
++ = ' ';
1212 char* TANSIParser::ParseANSIBuffer(char* pszBuffer
, char* pszBufferEnd
)
1215 return PrintBuffer(pszBuffer
, pszBufferEnd
);
1218 unsigned char tmpc
= *(unsigned char *)pszBuffer
;
1221 return ParseEscape(pszBuffer
, pszBufferEnd
);
1224 // if((fast_write && tmpc < 32) ||
1225 // !print_ctrl && (tmpc < 32 || (EightBit_Ansi &&
1226 // (tmpc > 128 && tmpc < 128 + ' ')))) {
1228 // We shouldn't print ctrl characters when fast write is enabled
1229 // and ctrl chars are disabled (Paul Brannan 9/1/98)
1231 // From the Linux kernel (Paul Brannan 12/5/98):
1232 /* A bitmap for codes <32. A bit of 1 indicates that the code
1233 * corresponding to that bit number invokes some special action
1234 * (such as cursor movement) and should not be displayed as a
1235 * glyph unless the disp_ctrl mode is explicitly enabled.
1237 const long CTRL_ACTION
= 0x0d00ff81;
1238 const long CTRL_ALWAYS
= 0x0800f501;
1239 if(!(((print_ctrl
?CTRL_ALWAYS
:CTRL_ACTION
)>>tmpc
)&1)) {
1241 Console
.WriteString((char *)&tmpc
, 1);
1251 // I.Ioannou 5/30/98
1257 // destructive backspace
1259 // Added option for destructive backspace (Paul Brannan 5/13/98)
1260 // Changed to ConWriteCtrlString so that the cursor position can be
1261 // updated (Paul Brannan 5/25/98)
1262 if(ini
.get_dstrbksp()) {
1263 Console
.WriteCtrlChar('\b');
1264 Console
.WriteString(" ", 1);
1265 Console
.WriteCtrlChar('\b');
1267 else Console
.WriteCtrlChar('\b');
1275 int x
= Console
.GetCursorX();
1277 Console
.SetCursorPosition(tab_stops
[x
], Console
.GetCursorY());
1283 // Test for local echo (Paul Brannan 8/25/98)
1284 if(Network
.get_local_echo() || newline_mode
) // &&
1285 Console
.WriteCtrlChar('\x0d');
1286 Console
.WriteCtrlChar('\x0a');
1293 Console
.ClearScreen();
1294 Console
.SetRawCursorPosition(Console
.GetCursorX(), 1); // changed fm 1
1298 Console
.WriteCtrlChar('\x0d');
1303 case 14: // shift out of alternate chararcter set
1305 Charmap
.setmap(map_G1
); // Paul Brannan 6/25/98
1309 case 15: // shift in
1311 Charmap
.setmap(map_G0
); // Paul Brannan 6/25/98
1315 // Paul Brannan 9/1/98 - Is this okay?
1323 // added by I.Ioannou 06 April, 1997
1324 // In 8 bit systems the server may send 0x9b instead of ESC[
1325 // Well, this will produce troubles in Greek 737 Code page
1326 // which uses 0x9b as the small "delta" - and I thing that there
1327 // is another European country with the same problem.
1328 // If we have to stay 8-bit clean we may have to
1329 // give the ability of ROM characters (ESC[11m),
1330 // for striped 8'th bit (ESC[12m) as SCO does,
1331 // or a parameter at compile (or run ?) time.
1332 // We now check for a flag in the ini file (Paul Brannan 5/13/98)
1333 // We also handle any 8-bit ESC sequence (Paul Brannan 6/28/98)
1334 if(ini
.get_eightbit_ansi() && (tmpc
> 128 && tmpc
< 128 + ' ')) {
1335 // There's a chance the sequence might not parse. If this happens
1336 // then pszBuffer will be one character too far back, since
1337 // ParseEscape is expecting two characters, not one.
1338 // In that case we must handle it.
1339 char *pszCurrent
= pszBuffer
;
1340 pszBuffer
= ParseEscape(pszBuffer
, pszBufferEnd
);
1341 if(pszBuffer
< pszCurrent
) pszBuffer
= pszCurrent
;
1344 char* pszCurrent
= pszBuffer
+ 1;
1345 // I.Ioannou 04 Sep 1997 FIXME with ESC[11m must show chars < 32
1346 // Fixed (Paul Brannan 6/28/98)
1347 while ((pszCurrent
< pszBufferEnd
) && (!iscntrl(*pszCurrent
))) {
1348 // I.Ioannou 04 Sep 1997 strip on high bit
1349 if ( (inGraphMode
) && (*pszCurrent
> (char)32) )
1350 *pszCurrent
|= 0x80 ;
1354 // Note that this may break dumpfiles slightly.
1355 // If 'B' is set to anything other than ASCII, this will cause problems
1356 // (Paul Brannan 6/28/98)
1357 if(current_map
!= 'B' && Charmap
.enabled
)
1358 Charmap
.translate_buffer(pszBuffer
, pszCurrent
);
1360 last_char
= *(pszCurrent
-1); // TITUS++: Remember last char
1363 pszBuffer
+= Console
.WriteStringFast(pszBuffer
,
1364 pszCurrent
- pszBuffer
);
1366 pszBuffer
+= Console
.WriteString(pszBuffer
,
1367 pszCurrent
- pszBuffer
);
1373 // Added by I.Ioannou 06 April, 1997
1374 // Print the buffer until you reach ESC[4i
1375 char* TANSIParser::PrintBuffer(char* pszBuffer
, char* pszBufferEnd
) {
1376 // Check if we have enough characters in buffer.
1377 if ((pszBufferEnd
- pszBuffer
) < 4)
1381 tmpChar
= pszBuffer
;
1382 if ( *tmpChar
== 27 ) {
1384 if ( *tmpChar
== '[' ) {
1386 if ( *tmpChar
== '4' ) {
1388 if ( *tmpChar
== 'i' ) {
1389 InPrintMode
= 0; // Stop Print Log
1390 if ( printfile
!= NULL
)
1399 if (printfile
!= NULL
) {
1400 fputc( *pszBuffer
, printfile
);
1408 /* - PrintGoodChars( pszHead, pszTail ) - - - - - - - - - - - - - - - - - - -
1411 Mark Miesfield 09/24/2000
1413 Prints the characters in a buffer, from the specified head to the specified
1414 tail, to standard out, skipping any control characters or ANSI escape
1417 Parameters on entry:
1418 pszHead -> Starting point in buffer.
1420 pszTail -> Ending point in buffer.
1423 Pointer to the first character in the buffer that was not output to
1424 standard out. (Since no error checking is done, this is in effect
1429 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1431 char * TANSIParser::PrintGoodChars( char * pszHead
, char * pszTail
) {
1433 while ( pszHead
< pszTail
) {
1434 if ( iscntrl( *pszHead
) ) {
1435 switch ( *(pszHead
++) ) {
1445 switch ( *(pszHead
++) ) {
1453 case '%': pszHead
++; break;
1455 while ( (pszHead
< pszTail
) && (*pszHead
< '?') )
1470 putc( *(pszHead
++), stdout
);
1474 // End of function: PrintGoodChars( pszHead, pszTail )