merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / apps / utils / net / telnet / src / ansiprsr.cpp
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
6 //
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.
11 //
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.
16 //
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.
20 //
21 //I.Ioannou
22 //roryt@hol.gr
23 //
24 ///////////////////////////////////////////////////////////////////////////
25
26 ///////////////////////////////////////////////////////////////////////////////
27 //
28 // Module: ansiprsr.cpp
29 //
30 // Contents: ANSI parser base class
31 //
32 // Product: telnet
33 //
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
45 // Version 2.0
46 //
47 // 13.Jul.1995 igor.milavec@uni-lj.si
48 // Original code
49 //
50 ///////////////////////////////////////////////////////////////////////////////
51
52 #include <windows.h>
53 #include <string.h>
54 #include "ansiprsr.h"
55
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) {
62 Init();
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");
68 }else {
69 dumpfile = NULL;
70 }
71 InPrintMode = 0;
72 printfile = NULL;
73
74 fast_write = ini.get_fast_write(); // Paul Brannan 6/28/98
75 Scroller.init(&StripBuffer);
76 }
77
78 TANSIParser::~TANSIParser(){
79 if (dumpfile) fclose (dumpfile);
80 // Added I.Ioannou 06 April, 1997
81 if (printfile != NULL) fclose (printfile);
82 }
83
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);
90 current_map = 'B';
91
92 ignore_margins = 0;
93 vt52_mode = 0;
94 print_ctrl = 0;
95 newline_mode = false;
96
97 KeyTrans.clear_ext_mode();
98
99 iSavedCurY = 0; // Reset Variables
100 iSavedCurX = 0;
101 inGraphMode = 0;
102 Console.SetScroll(-1, -1);
103 Console.Normal(); // Reset Attributes
104
105 // Set tabs stops
106 resetTabStops();
107 }
108
109 void TANSIParser::ResetTerminal() {
110 Init();
111 Console.ClearScreen(); // Clear Screen
112 Console.SetRawCursorPosition(0,0); // Home Cursor
113 }
114 void TANSIParser::SaveCurY(int iY){
115 iSavedCurY=iY;
116 }
117
118 void TANSIParser::SaveCurX(int iX){
119 iSavedCurX=iX;
120 }
121
122 void TANSIParser::resetTabStops() {
123 for(int j = 0; j < MAX_TAB_POSITIONS; j++) {
124 tab_stops[j] = 8 + j - (j%8);
125 }
126 }
127
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
131 // for the colors
132 if(TextAttrib >= 30) {
133 if(TextAttrib <= 37) {
134 Console.SetForeground(ANSIColors[TextAttrib-30]);
135 return;
136 } else if((TextAttrib >= 40) && (TextAttrib <= 47)) {
137 Console.SetBackground(ANSIColors[TextAttrib-40]);
138 return;
139 }
140 }
141
142 switch (TextAttrib){
143 // Text Attributes
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
154 case 10:
155 // I.Ioannou 04 Sep 1997 turn on/off high bit
156 inGraphMode = 0;
157 print_ctrl = 0;
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)
164 case 11:
165 inGraphMode = 0;
166 print_ctrl = 1;
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
171 // as ROM chars
172 case 12:
173 inGraphMode = 1;
174 print_ctrl = 1;
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.
180
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
187
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).
194 */
195 Console.UnderlineOn();
196 Console.SetForeground(ini.get_normal_fg());
197 break;
198 case 39: /* ANSI X3.64-1979 (SCO-ish?)
199 * Disable underline option.
200 * Reset colour to default? It did this
201 * before...
202 */
203 Console.UnderlineOff();
204 Console.SetForeground(ini.get_normal_fg());
205 break;
206 case 49:
207 Console.SetBackground(ini.get_normal_bg());
208 break;
209
210 }
211 }
212
213 void TANSIParser::ConSetCursorPos(int x, int y) {
214 if(ignore_margins)
215 Console.SetRawCursorPosition(x, y);
216 else
217 Console.SetCursorPosition(x, y);
218 }
219
220 char* TANSIParser::GetTerminalID()
221 {
222 return "\033[?1;2c";
223 }
224
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)
228
229 #ifdef __BORLANDC__
230 // argsused doesn't work on MSVC++
231 #pragma argsused
232 #endif
233
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
245
246 char* TANSIParser::ParseEscapeANSI(char* pszBuffer, char* pszBufferEnd)
247 {
248
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'
254
255 // TITUS: Simplification of the code: Assume default count of 1 in case
256 // there are no parameters.
257 char tmpc;
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;
261 DWORD flag = 0;
262 int missing_param = 0;
263
264 // Get parameters from escape sequence.
265 while ((tmpc = *pszBuffer) <= '?') {
266
267 if(tmpc < '0' || tmpc > '9') {
268 // Check for parameter delimiter.
269 if(tmpc == ';') {
270 // This is a hack (Paul Brannan 6/27/98)
271 if(*(pszBuffer - 1) == '[') missing_param = iCurrentParam+1;
272 pszBuffer++;
273 continue;
274 }
275
276 // It is legal to have control characters inside ANSI sequences
277 // (Paul Brannan 6/26/98)
278 if(tmpc < ' ') {
279 Console.WriteCtrlChar(tmpc);
280 pszBuffer++;
281 continue;
282 }
283
284 // A new way of handling flags (Paul Brannan 12/2/98)
285 switch(tmpc) {
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;
296 }
297
298 pszBuffer++;
299 }
300
301 // Got Numerical Parameter.
302 iParam[iCurrentParam] = strtoul(pszBuffer, &pszBuffer, 10);
303 if (iCurrentParam < nParam)
304 iCurrentParam++;
305 }
306
307 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
308 // So: If there is no digit, assume a count of 1
309
310 switch ((unsigned char)*pszBuffer++) {
311 // Insert Character
312 case '@':
313 if(iParam[0] == 0) iParam[0] = 1; // Paul Brannan 9/1/98
314 Console.InsertCharacter(iParam[0]); break;
315 // Move cursor up.
316 case 'A':
317 if(iParam[0] == 0) iParam[0] = 1;
318 Console.MoveCursorPosition(0, -iParam[0]); break;
319 // Move cursor down.
320 // Added by I.Ioannou 06 April, 1997
321 case 'B':
322 case 'e':
323 if(iParam[0] == 0) iParam[0] = 1;
324 Console.MoveCursorPosition(0, iParam[0]);
325 break;
326 // Move cursor right.
327 // Added by I.Ioannou 06 April, 1997
328 case 'C':
329 case 'a':
330 // Handle cursor size sequences (Jose Cesar Otero Rodriquez and
331 // Paul Brannan, 3/27/1999)
332 if(flag & FLAG_EQUAL) {
333 switch(iParam[0]) {
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);
338 }
339 } else {
340 if(iParam[0] == 0) iParam[0] = 1;
341 Console.MoveCursorPosition(iParam[0], 0);
342 break;
343 }
344 // Move cursor left.
345 case 'D':
346 if(iParam[0] == 0) iParam[0] = 1;
347 Console.MoveCursorPosition(-iParam[0], 0);
348 break;
349 // Move cursor to beginning of line, p lines down.
350 // Added by I.Ioannou 06 April, 1997
351 case 'E':
352 Console.MoveCursorPosition(-Console.GetCursorX(), iParam[0]);
353 break;
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)
357 case 'F':
358 if(flag & FLAG_EQUAL)
359 Console.setDefaultFg(iParam[0]);
360 else
361 Console.MoveCursorPosition(-Console.GetCursorX(), -iParam[0]);
362 break;
363 // Go to column p
364 // Added by I.Ioannou 06 April, 1997
365 // With '=' this changes the default bg color (Paul Brannan 6/27/98)
366 case '`':
367 case 'G': // 'G' is from Linux kernel sources
368 if(flag & FLAG_EQUAL) {
369 Console.setDefaultBg(iParam[0]);
370 } else {
371 if (iCurrentParam < 1) // Alter Default
372 iParam[0] = 0;
373 // this was backward, and we should subtract 1 from x
374 // (Paul Brannan 5/27/98)
375 ConSetCursorPos(iParam[0] - 1, Console.GetCursorY());
376 }
377 break;
378 // Set cursor position.
379 case 'f':
380 case 'H':
381 if (iCurrentParam < 2 || iParam[1] < 1)
382 iParam[1] = 1;
383 ConSetCursorPos(iParam[1] - 1, iParam[0] - 1);
384 break;
385 // Clear screen
386 case 'J':
387 if ( iCurrentParam < 1 ) iParam[0] = 0; // Alter Default
388 switch (iParam[0]) {
389 case 0: Console.ClearEOScreen(); break;
390 case 1: Console.ClearBOScreen(); break;
391 case 2:
392 Console.ClearScreen();
393 Console.SetRawCursorPosition(0, 0);
394 break;
395 }
396 break;
397 // Clear line
398 case 'K':
399 if (iCurrentParam < 1) // Alter Default
400 iParam[0] = 0;
401 switch (iParam[0]) {
402 case 0: Console.ClearEOLine(); break;
403 case 1: Console.ClearBOLine(); break;
404 case 2: Console.ClearLine(); break;
405 }
406 break;
407 // Insert p new, blank lines.
408 // Added by I.Ioannou 06 April, 1997
409 case 'L':
410 {
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]);
414 break;
415 }
416 // Delete p lines.
417 // Added by I.Ioannou 06 April, 1997
418 case 'M':
419 {
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);
423 break;
424 }
425 // DELETE CHAR
426 case 'P':
427 Console.DeleteCharacter(iParam[0]);
428 break;
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 !!
434 case 'S':
435 {
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]);
439 break;
440 }
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 !!
446 case 'T':
447 {
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]);
451 break;
452 }
453 // Erases p characters up to the end of line
454 // Added by I.Ioannou 06 April, 1997
455 case 'X':
456 {
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);
464 break;
465 }
466 // Go back p tab stops
467 // Added by I.Ioannou 06 April, 1997
468 // Implemented by Paul Brannan, 4/13/2000
469 case 'Z':
470 {
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());
475 }
476 break;
477 // Get Terminal ID
478 case 'c':
479 {
480 char* szTerminalId = GetTerminalID();
481 Network.WriteString(szTerminalId, strlen(szTerminalId));
482 break;
483 }
484 // TITUS++ 2. November 1998: Repeat Character.
485 case 'b':
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)
489
490 if ( iParam[0] > 149 ) iParam[0] = 149;
491 memset(buf, last_char, iParam[0]);
492 buf[iParam[0]] = 0;
493 if ( fast_write )
494 Console.WriteStringFast(buf, iParam[0]);
495 else
496 Console.WriteString(buf, iParam[0]);
497 // } /* IF */
498 break;
499 // Go to line p
500 // Added by I.Ioannou 06 April, 1997
501 case 'd':
502 if (iCurrentParam < 1) // Alter Default
503 iParam[0] = 0;
504 // this was backward, and we should subtract 1 from y
505 // (Paul Brannan 5/27/98)
506 ConSetCursorPos(Console.GetCursorX(), iParam[0] - 1);
507 break;
508 // iBCS2 tab erase
509 // Added by I.Ioannou 06 April, 1997
510 case 'g':
511 if (iCurrentParam < 1) // Alter Default
512 iParam[0] = 0;
513 switch (iParam[0]) {
514 case 0:
515 {
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];
520 }
521 }
522 break;
523 case 2:
524 // I think this might be "set as default?"
525 break;
526 case 3:
527 {
528 // Clear all tab stops
529 for(int j = 0; j < MAX_TAB_POSITIONS; j++)
530 tab_stops[j] = -1;
531 }
532 break;
533 }
534 break;
535 // Set extended mode
536 case 'h':
537 {
538 for (int i = 0; i < iCurrentParam; i++) {
539 // Changed to a switch statement (Paul Brannan 5/27/98)
540 if(flag & FLAG_QMARK) {
541 switch(iParam[i]) {
542 case 1: // App cursor keys
543 KeyTrans.set_ext_mode(APP_KEY);
544 break;
545 case 2: // VT102 mode
546 vt52_mode = 0;
547 KeyTrans.unset_ext_mode(APP2_KEY);
548 break;
549 case 3: // 132 columns
550 if(ini.get_wide_enable()) {
551 Console.SetWindowSize(132, -1);
552 }
553 break;
554 case 4: // smooth scrolling
555 break;
556 case 5: // Light background
557 Console.Lightbg();
558 break;
559 case 6: // Stay in margins
560 ignore_margins = 0;
561 break;
562 case 7:
563 Console.setLineWrap(true);
564 break;
565 case 8: // Auto-repeat keys
566 break;
567 case 18: // Send FF to printer
568 break;
569 case 19: // Entire screen legal for printer
570 break;
571 case 25: // Visible cursor
572 break;
573 case 66: // Application numeric keypad
574 break;
575 default:
576 #ifdef DEBUG
577 Console.Beep();
578 #endif
579 break;
580 }
581 } else {
582 switch(iParam[i]) {
583 case 2: // Lock keyboard
584 break;
585 case 3: // Act upon control codes (PB 12/5/98)
586 print_ctrl = 0;
587 break;
588 case 4: // Set insert mode
589 Console.InsertMode(1);
590 break;
591 case 12: // Local echo off
592 break;
593 case 20: // Newline sends cr/lf
594 KeyTrans.set_ext_mode(APP4_KEY);
595 newline_mode = true;
596 break;
597 default:
598 #ifdef DEBUG
599 Console.Beep();
600 #endif
601 break;
602 }
603 }
604 }
605 }
606 break;
607 // Print Screen
608 case 'i':
609 if (iCurrentParam < 1)
610 iParam[0]=0;
611 switch (iParam[0]){
612 case 0: break; // Print Screen
613 case 1: break; // Print Line
614 // Added I.Ioannou 06 April, 1997
615 case 4:
616 // Stop Print Log
617 InPrintMode = 0;
618 if ( printfile != NULL )
619 fclose(printfile);
620 break;
621 case 5:
622 // Start Print Log
623 printfile = fopen(ini.get_printer_name(), "ab");
624 if (printfile != NULL) InPrintMode = 1;
625 break;
626 }
627 break;
628 // Unset extended mode
629 case 'l':
630 {
631 for (int i = 0; i < iCurrentParam; i++) {
632 // Changed to a switch statement (Paul Brannan 5/27/98)
633 if(flag & FLAG_QMARK) {
634 switch(iParam[i]) {
635 case 1: // Numeric cursor keys
636 KeyTrans.unset_ext_mode(APP_KEY);
637 break;
638 case 2: // VT52 mode
639 vt52_mode = 1;
640 KeyTrans.set_ext_mode(APP2_KEY);
641 break;
642 case 3: // 80 columns
643 if(ini.get_wide_enable()) {
644 Console.SetWindowSize(80, -1);
645 }
646 break;
647 case 4: // jump scrolling
648 break;
649 case 5: // Dark background
650 Console.Darkbg();
651 break;
652 case 6: // Ignore margins
653 ignore_margins = 1;
654 break;
655 case 7:
656 Console.setLineWrap(false);
657 break;
658 case 8: // Auto-repeat keys
659 break;
660 case 19: // Only send scrolling region to printer
661 break;
662 case 25: // Invisible cursor
663 break;
664 case 66: // Numeric keypad
665 break;
666 default:
667 #ifdef DEBUG
668 Console.Beep();
669 #endif
670 break;
671 }
672 } else {
673 switch(iParam[i]) {
674 case 2: // Unlock keyboard
675 break;
676 case 3: // Display control codes (PB 12/5/98)
677 print_ctrl = 1;
678 break;
679 case 4: // Set overtype mode
680 Console.InsertMode(0);
681 break;
682 case 12: // Local echo on
683 break;
684 case 20: // sends lf only
685 KeyTrans.unset_ext_mode(APP4_KEY);
686 newline_mode = false;
687 break;
688 default:
689 #ifdef DEBUG
690 Console.Beep();
691 #endif
692 break;
693 }
694 }
695 }
696 }
697 break;
698 // Set color
699 case 'm':
700 if(missing_param) Console.Normal();
701 if(iCurrentParam == 0) {
702 Console.Normal();
703 } else {
704 for(int i = 0; i < iCurrentParam; i++)
705 ConSetAttribute(iParam[i]);
706 }
707 break;
708 // report cursor position Row X Col
709 case 'n':
710 if (iCurrentParam == 1 && iParam[0]==5) {
711 // report the cursor position
712 Network.WriteString("\x1B[0n", 6);
713 break;
714 }
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[";
720
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");
727
728 Network.WriteString(szCursorReport, strlen(szCursorReport));
729
730 }
731 break;
732 // Miscellaneous weird sequences (Paul Brannan 6/27/98)
733 case 'p':
734 // Set conformance level
735 if(flag & FLAG_QUOTE) {
736 break;
737 }
738 // Soft terminal reset
739 if(flag & FLAG_EXCLAM) {
740 break;
741 }
742 // Report mode settings
743 if(flag & FLAG_DOLLAR) {
744 break;
745 }
746 break;
747 // Scroll Screen
748 case 'r':
749 if (iCurrentParam < 1) {
750 // Enable scrolling for entire display
751 Console.SetScroll(-1, -1);
752 break;
753 }
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(),
761 // iParam[0] - 1);
762 // }
763 // if(Console.GetRawCursorY() > iParam[1] - 1) {
764 // Console.SetRawCursorPosition(Console.GetCursorX(),
765 // iParam[1] - 1);
766 // }
767 }
768 // Move the cursor to the home position (Paul Brannan 12/2/98)
769 Console.SetCursorPosition(0, 0);
770 break;
771 // Save cursor position
772 case 's':
773 SaveCurY(Console.GetRawCursorY());
774 SaveCurX(Console.GetRawCursorX());
775 break;
776 // Restore cursor position
777 case 'u':
778 Console.SetRawCursorPosition(iSavedCurX, iSavedCurY);
779 break;
780 // DEC terminal report (Paul Brannan 6/28/98)
781 case 'x':
782 if(iParam[0])
783 Network.WriteString("\033[3;1;1;128;128;1;0x", 20);
784 else
785 Network.WriteString("\033[2;1;1;128;128;1;0x", 20);
786 break;
787 default:
788 #ifdef DEBUG
789 Console.Beep();
790 #endif
791 break;
792 }
793
794 return pszBuffer;
795 }
796
797 #ifdef MTE_SUPPORT
798 // Added by Frediano Ziglio, 5/31/2000
799 // MTE extension
800 // initially copied from ParseEscapeANSI
801 char* TANSIParser::ParseEscapeMTE(char* pszBuffer, char* pszBufferEnd)
802 {
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.
810 char tmpc;
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;
814 char sRepeat[2];
815
816 // Get parameters from escape sequence.
817 while ((tmpc = *pszBuffer) <= '?') {
818 if(tmpc < '0' || tmpc > '9') {
819 // Check for parameter delimiter.
820 if(tmpc == ';') {
821 pszBuffer++;
822 continue;
823 }
824 pszBuffer++;
825 }
826
827 // Got Numerical Parameter.
828 iParam[iCurrentParam] = strtoul(pszBuffer, &pszBuffer, 10);
829 if (iCurrentParam < nParam)
830 iCurrentParam++;
831 }
832
833 //~~~ TITUS: Apparently the digit is optional (look at termcap or terminfo)
834 // So: If there is no digit, assume a count of 1
835
836 switch ((unsigned char)*pszBuffer++) {
837 case 'A':
838 // set colors
839 if (iCurrentParam < 2 )
840 break;
841 if (iParam[0] <= 15 && iParam[1] <= 15)
842 Console.SetAttrib( (iParam[1] << 4) | iParam[0] );
843 break;
844
845 case 'R':
846 // define region
847 mteRegionXF = -1;
848 if (iCurrentParam < 2 )
849 break;
850 mteRegionXF = iParam[1]-1;
851 mteRegionYF = iParam[0]-1;
852 break;
853
854 case 'F':
855 // fill with char
856 {
857 if (mteRegionXF == -1 || iCurrentParam < 1)
858 break;
859 sRepeat[0] = (char)iParam[0];
860 sRepeat[1] = '\0';
861 int xi = Console.GetCursorX(),yi = Console.GetCursorY();
862 int xf = mteRegionXF;
863 int yf = mteRegionYF;
864 mteRegionXF = -1;
865 for(int y=yi;y<=yf;++y)
866 {
867 Console.SetCursorPosition(xi,y);
868 for(int x=xi;x<=xf;++x)
869
870 Console.WriteStringFast(sRepeat,1);
871 }
872 }
873 break;
874
875 case 'S':
876 // Scroll region
877 {
878 if (mteRegionXF == -1 || iCurrentParam < 2)
879 break;
880 int /*x = Console.GetCursorX(),*/y = Console.GetCursorY();
881 // int xf = mteRegionXF;
882 int yf = mteRegionYF;
883 mteRegionXF = -1;
884 // !!! don't use x during scroll
885 int diff = (iParam[0]-1)-y;
886 if (diff<0)
887 Console.ScrollDown(y-1,yf,diff);
888 else
889 Console.ScrollDown(y,yf+1,diff);
890 }
891 break;
892 // Meridian main version ??
893 case 'x':
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);
899 break;
900 // query ??
901 case 'Q':
902 if (iParam[0] == 1)
903 Network.WriteString("\033vga.",5);
904 break;
905 default:
906 #ifdef DEBUG
907 Console.Beep();
908 #endif
909 break;
910 }
911
912 return pszBuffer;
913 }
914 #endif
915
916 char* TANSIParser::ParseEscape(char* pszBuffer, char* pszBufferEnd) {
917 char *pszChar;
918
919 // Check if we have enough characters in buffer.
920 if ((pszBufferEnd - pszBuffer) < 2)
921 return pszBuffer;
922
923 // I.Ioannou 04 Sep 1997
924 // there is no need for pszBuffer++; after each command
925
926 // Decode the command.
927 pszBuffer++;
928
929 switch (*pszBuffer++) {
930 case 'A': // Cursor up
931 Console.MoveCursorPosition(0, -1);
932 break;
933 // Cursor down
934 case 'B':
935 Console.MoveCursorPosition(0, 1);
936 break;
937 // Cursor right
938 case 'C':
939 Console.MoveCursorPosition(1, 0);
940 break;
941 // LF *or* cursor left (Paul Brannan 6/27/98)
942 case 'D':
943 if(vt52_mode)
944 Console.MoveCursorPosition(-1, 0);
945 else
946 Console.index();
947 break;
948 // CR/LF (Paul Brannan 6/26/98)
949 case 'E':
950 Console.WriteCtrlString("\r\n", 2);
951 break;
952 // Special graphics char set (Paul Brannan 6/27/98)
953 case 'F':
954 Charmap.setmap('0');
955 break;
956 // ASCII char set (Paul Brannan 6/27/98)
957 case 'G':
958 Charmap.setmap('B');
959 break;
960 // Home cursor/tab set
961 case 'H':
962 if(ini.get_vt100_mode()) {
963 int x = Console.GetCursorX();
964 if(x != 0) {
965 int t = tab_stops[x - 1];
966 for(int j = x - 1; j >= 0 && tab_stops[j] == t; j--)
967 tab_stops[j] = x;
968 }
969 } else {
970 // I.Ioannou 04 Sep 1997 (0,0) not (1,1)
971 ConSetCursorPos(0, 0);
972 }
973 break;
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)
977 case 'I':
978 Console.reverse_index();
979 break;
980 // Erase end of screen
981 case 'J':
982 Console.ClearEOScreen();
983 break;
984 // Erase EOL
985 case 'K':
986 Console.ClearEOLine();
987 break;
988 // Scroll Up one line //Reverse index
989 case 'M':
990 Console.reverse_index();
991 break;
992 // Direct cursor addressing
993 case 'Y':
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] - ' ');
998 pszBuffer+=2;
999 } else {
1000 pszBuffer--; // Paul Brannan 6/26/98
1001 }
1002 break;
1003 // Terminal ID Request
1004 case 'Z':
1005 {
1006 char* szTerminalId = GetTerminalID();
1007 Network.WriteString(szTerminalId, strlen(szTerminalId));
1008 break;
1009 }
1010 // reset terminal to defaults
1011 case 'c':
1012 ResetTerminal();
1013 break;
1014 // Enter alternate keypad mode
1015 case '=':
1016 KeyTrans.set_ext_mode(APP3_KEY);
1017 break;
1018 // Exit alternate keypad mode
1019 case '>':
1020 KeyTrans.unset_ext_mode(APP3_KEY);
1021 break;
1022 // Enter ANSI mode
1023 case '<':
1024 KeyTrans.unset_ext_mode(APP2_KEY); // exit vt52 mode
1025 break;
1026 // Graphics processor on (See note 3)
1027 case '1':
1028 break;
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;
1038 }
1039 } else {
1040 pszBuffer--;
1041 }
1042 break;
1043 // Graphics processor off (See note 3)
1044 case '2':
1045 break;
1046 // Save cursor and attribs
1047 case '7':
1048 SaveCurY(Console.GetRawCursorY());
1049 SaveCurX(Console.GetRawCursorX());
1050 iSavedAttributes = Console.GetAttrib();
1051 break;
1052 // Restore cursor position and attribs
1053 case '8':
1054 Console.SetRawCursorPosition(iSavedCurX, iSavedCurY);
1055 Console.SetAttrib(iSavedAttributes);
1056 break;
1057 // Set G0 map (Paul Brannan 6/25/98)
1058 case '(':
1059 if (pszBuffer < pszBufferEnd) {
1060 map_G0 = *pszBuffer;
1061 if(current_map == 0) Charmap.setmap(map_G0);
1062 pszBuffer++;
1063 } else {
1064 pszBuffer--;
1065 }
1066 break;
1067 // Set G1 map (Paul Brannan 6/25/98)
1068 case ')':
1069 if (pszBuffer < pszBufferEnd) {
1070 map_G1 = *pszBuffer;
1071 if(current_map == 1) Charmap.setmap(map_G1);
1072 pszBuffer++;
1073 } else {
1074 pszBuffer--;
1075 }
1076 break;
1077 // This doesn't do anything, as far as I can tell, but it does take
1078 // a parameter (Paul Brannan 6/27/98)
1079 case '%':
1080 if (pszBuffer < pszBufferEnd) {
1081 pszBuffer++;
1082 } else {
1083 pszBuffer--;
1084 }
1085 break;
1086 // ANSI escape sequence
1087 case '[':
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 <= '?'))
1092 pszChar++;
1093 if (pszChar == pszBufferEnd)
1094 pszBuffer -= 2;
1095 else
1096 pszBuffer = ParseEscapeANSI(pszBuffer, pszBufferEnd);
1097 break;
1098 #ifdef MTE_SUPPORT
1099 case '~':
1100 // Frediano Ziglio, 5/31/2000
1101 // Meridian Terminal Emulator extension
1102 // !!! same as ANSI
1103 // !!! should put in MTE procedure
1104 pszChar = pszBuffer;
1105 while ((pszChar < pszBufferEnd) && (*pszChar <= '?'))
1106 pszChar++;
1107 if (pszChar == pszBufferEnd)
1108 pszBuffer -= 2;
1109 else
1110 pszBuffer = ParseEscapeMTE(pszBuffer, pszBufferEnd);
1111 break;
1112 #endif
1113 default:
1114 #ifdef DEBUG
1115 Console.Beep();
1116 #endif
1117 break;
1118 }
1119
1120 return pszBuffer;
1121 }
1122
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
1129 char * pszResult;
1130
1131 // Parse the buffer for ANSI or display
1132 while (pszHead < pszTail) {
1133 if(!ini.get_output_redir()) {
1134 pszResult = ParseANSIBuffer(pszHead, pszTail);
1135 } else {
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);
1141 } else {
1142 DWORD Result;
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;
1149 }
1150 }
1151 if (dumpfile)
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;
1156 }
1157 // return the new head to the buffer
1158 return pszHead;
1159 }
1160
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;
1167
1168 while(pszHead < pszTail) {
1169 if(iscntrl(*pszHead)) {
1170 switch(*(pszHead++)) {
1171 case 8:
1172 case 127:
1173 if(c>0) {
1174 if(!(c%width)) lines--;
1175 c--;
1176 pszBuf--;
1177 }
1178 break;
1179 case 10: lines++;
1180 case 13:
1181 *(pszBuf++) = *(pszHead - 1);
1182 c = 0;
1183 break;
1184 case 27:
1185 switch(*(pszHead++)) {
1186 case 'Y': pszHead += 2; break;
1187 case '#':
1188 case '(':
1189 case ')':
1190 case '%': pszHead++; break;
1191 case '[':
1192 while((pszHead < pszTail) && (*pszHead < '?'))
1193 pszHead++;
1194 pszHead++;
1195 break;
1196 }
1197 }
1198 } else {
1199 *(pszBuf++) = *(pszHead++);
1200 c++;
1201 }
1202 if(c != 0 && !(c%width))
1203 lines++;
1204 }
1205
1206 // Fill in the end of the buffer with blanks
1207 while(pszBuf <= pszTail) *pszBuf++ = ' ';
1208
1209 return lines;
1210 }
1211
1212 char* TANSIParser::ParseANSIBuffer(char* pszBuffer, char* pszBufferEnd)
1213 {
1214 if(InPrintMode) {
1215 return PrintBuffer(pszBuffer, pszBufferEnd);
1216 }
1217
1218 unsigned char tmpc = *(unsigned char *)pszBuffer;
1219
1220 if(tmpc == 27) {
1221 return ParseEscape(pszBuffer, pszBufferEnd);
1222 }
1223
1224 // if((fast_write && tmpc < 32) ||
1225 // !print_ctrl && (tmpc < 32 || (EightBit_Ansi &&
1226 // (tmpc > 128 && tmpc < 128 + ' ')))) {
1227
1228 // We shouldn't print ctrl characters when fast write is enabled
1229 // and ctrl chars are disabled (Paul Brannan 9/1/98)
1230 if(tmpc < 32) {
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.
1236 */
1237 const long CTRL_ACTION = 0x0d00ff81;
1238 const long CTRL_ALWAYS = 0x0800f501;
1239 if(!(((print_ctrl?CTRL_ALWAYS:CTRL_ACTION)>>tmpc)&1)) {
1240
1241 Console.WriteString((char *)&tmpc, 1);
1242 pszBuffer++;
1243 return pszBuffer;
1244 }
1245
1246 switch (tmpc) {
1247 case 0:
1248 pszBuffer++;
1249 break;
1250
1251 // I.Ioannou 5/30/98
1252 case 7:
1253 Console.Beep();
1254 pszBuffer++;
1255 break;
1256
1257 // destructive backspace
1258 case 8:
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');
1266 }
1267 else Console.WriteCtrlChar('\b');
1268 pszBuffer++;
1269 break;
1270
1271 // horizontal tab
1272 case 9:
1273 {
1274 pszBuffer++;
1275 int x = Console.GetCursorX();
1276 if(x != -1)
1277 Console.SetCursorPosition(tab_stops[x], Console.GetCursorY());
1278 }
1279 break;
1280
1281 // Line Feed Char
1282 case 10:
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');
1287 pszBuffer++;
1288 break;
1289
1290 // form feed
1291 case 12:
1292 pszBuffer++;
1293 Console.ClearScreen();
1294 Console.SetRawCursorPosition(Console.GetCursorX(), 1); // changed fm 1
1295 break;
1296
1297 case 13:
1298 Console.WriteCtrlChar('\x0d');
1299 pszBuffer++;
1300
1301 break;
1302
1303 case 14: // shift out of alternate chararcter set
1304 pszBuffer++;
1305 Charmap.setmap(map_G1); // Paul Brannan 6/25/98
1306 current_map = 1;
1307 break;
1308
1309 case 15: // shift in
1310 pszBuffer++;
1311 Charmap.setmap(map_G0); // Paul Brannan 6/25/98
1312 current_map = 0;
1313 break;
1314
1315 // Paul Brannan 9/1/98 - Is this okay?
1316 default:
1317 pszBuffer++;
1318 }
1319
1320 return pszBuffer;
1321 }
1322
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;
1342 }
1343
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 ;
1351 pszCurrent++;
1352 }
1353
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);
1359
1360 last_char = *(pszCurrent-1); // TITUS++: Remember last char
1361
1362 if(fast_write) {
1363 pszBuffer += Console.WriteStringFast(pszBuffer,
1364 pszCurrent - pszBuffer);
1365 } else {
1366 pszBuffer += Console.WriteString(pszBuffer,
1367 pszCurrent - pszBuffer);
1368 }
1369
1370 return pszBuffer;
1371 }
1372
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)
1378 return pszBuffer;
1379 char *tmpChar;
1380
1381 tmpChar = pszBuffer;
1382 if ( *tmpChar == 27 ) {
1383 tmpChar++;
1384 if ( *tmpChar == '[' ) {
1385 tmpChar++;
1386 if ( *tmpChar == '4' ) {
1387 tmpChar++;
1388 if ( *tmpChar == 'i' ) {
1389 InPrintMode = 0; // Stop Print Log
1390 if ( printfile != NULL )
1391 fclose(printfile);
1392 pszBuffer += 4;
1393 return pszBuffer;
1394 }
1395 }
1396 }
1397 }
1398
1399 if (printfile != NULL) {
1400 fputc( *pszBuffer, printfile);
1401 pszBuffer++;
1402 } else
1403 InPrintMode = 0;
1404
1405 return pszBuffer;
1406 }
1407
1408 /* - PrintGoodChars( pszHead, pszTail ) - - - - - - - - - - - - - - - - - - -
1409 -*
1410
1411 Mark Miesfield 09/24/2000
1412
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
1415 sequences.
1416
1417 Parameters on entry:
1418 pszHead -> Starting point in buffer.
1419
1420 pszTail -> Ending point in buffer.
1421
1422 Returns:
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
1425 pszTail.)
1426
1427 Side Effects:
1428 None.
1429 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1430 */
1431 char * TANSIParser::PrintGoodChars( char * pszHead, char * pszTail ) {
1432
1433 while ( pszHead < pszTail ) {
1434 if ( iscntrl( *pszHead ) ) {
1435 switch ( *(pszHead++) ) {
1436 case 10 :
1437 putc( 10, stdout );
1438 break;
1439
1440 case 13 :
1441 putc( 13, stdout );
1442 break;
1443
1444 case 27:
1445 switch ( *(pszHead++) ) {
1446 case 'Y':
1447 pszHead += 2;
1448 break;
1449
1450 case '#':
1451 case '(':
1452 case ')':
1453 case '%': pszHead++; break;
1454 case '[':
1455 while ( (pszHead < pszTail) && (*pszHead < '?') )
1456 pszHead++;
1457 pszHead++;
1458 break;
1459
1460 default :
1461 break;
1462 }
1463 break;
1464
1465 default :
1466 break;
1467 }
1468 }
1469 else
1470 putc( *(pszHead++), stdout );
1471 }
1472 return ( pszTail );
1473 }
1474 // End of function: PrintGoodChars( pszHead, pszTail )