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�rz.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 "precomp.h" 53 54 const int ANSIColors[] = {BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE}; 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 const 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 const 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", 4); 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 const 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 ) 1475