1 /* 2 * Copyright 2001-2009, Haiku, Inc. 3 * Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net> 4 * Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. 5 * Distributed under the terms of the MIT license. 6 */ 7 8 //! Escape sequence parse and character encoding. 9 10 #include "TermParse.h" 11 12 #include <ctype.h> 13 #include <errno.h> 14 #include <stdio.h> 15 #include <signal.h> 16 #include <string.h> 17 #include <unistd.h> 18 19 #include <Autolock.h> 20 #include <Beep.h> 21 #include <Message.h> 22 23 #include "CodeConv.h" 24 #include "TermConst.h" 25 #include "TerminalBuffer.h" 26 #include "VTparse.h" 27 28 29 extern int gUTF8GroundTable[]; /* UTF8 Ground table */ 30 extern int gCS96GroundTable[]; /* CS96 Ground table */ 31 extern int gISO8859GroundTable[]; /* ISO8859 & EUC Ground table */ 32 extern int gSJISGroundTable[]; /* Shift-JIS Ground table */ 33 34 extern int gEscTable[]; /* ESC */ 35 extern int gCsiTable[]; /* ESC [ */ 36 extern int gDecTable[]; /* ESC [ ? */ 37 extern int gScrTable[]; /* ESC # */ 38 extern int gIgnoreTable[]; /* ignore table */ 39 extern int gIesTable[]; /* ignore ESC table */ 40 extern int gEscIgnoreTable[]; /* ESC ignore table */ 41 extern int gMbcsTable[]; /* ESC $ */ 42 43 44 45 #define DEFAULT -1 46 #define NPARAM 10 // Max parameters 47 48 49 //! Get char from pty reader buffer. 50 inline status_t 51 TermParse::_NextParseChar(uchar &c) 52 { 53 if (fParserBufferOffset >= fParserBufferSize) { 54 // parser buffer empty 55 status_t error = _ReadParserBuffer(); 56 if (error != B_OK) 57 return error; 58 } 59 60 c = fParserBuffer[fParserBufferOffset++]; 61 62 return B_OK; 63 } 64 65 66 TermParse::TermParse(int fd) 67 : 68 fFd(fd), 69 fParseThread(-1), 70 fReaderThread(-1), 71 fReaderSem(-1), 72 fReaderLocker(-1), 73 fBufferPosition(0), 74 fReadBufferSize(0), 75 fParserBufferSize(0), 76 fParserBufferOffset(0), 77 fParserWaiting(false), 78 fBuffer(NULL), 79 fQuitting(true) 80 { 81 } 82 83 84 TermParse::~TermParse() 85 { 86 StopThreads(); 87 } 88 89 90 status_t 91 TermParse::StartThreads(TerminalBuffer *buffer) 92 { 93 if (fBuffer != NULL) 94 return B_ERROR; 95 96 fQuitting = false; 97 fBuffer = buffer; 98 99 status_t status = InitPtyReader(); 100 if (status < B_OK) { 101 fBuffer = NULL; 102 return status; 103 } 104 105 status = InitTermParse(); 106 if (status < B_OK) { 107 StopPtyReader(); 108 fBuffer = NULL; 109 return status; 110 } 111 112 return B_OK; 113 } 114 115 116 status_t 117 TermParse::StopThreads() 118 { 119 if (fBuffer == NULL) 120 return B_ERROR; 121 122 fQuitting = true; 123 124 StopPtyReader(); 125 StopTermParse(); 126 127 fBuffer = NULL; 128 129 return B_OK; 130 } 131 132 133 //! Initialize and spawn EscParse thread. 134 status_t 135 TermParse::InitTermParse() 136 { 137 if (fParseThread >= 0) 138 return B_ERROR; // we might want to return B_OK instead ? 139 140 fParseThread = spawn_thread(_escparse_thread, "EscParse", 141 B_DISPLAY_PRIORITY, this); 142 143 resume_thread(fParseThread); 144 145 return B_OK; 146 } 147 148 149 //! Initialize and spawn PtyReader thread. 150 status_t 151 TermParse::InitPtyReader() 152 { 153 if (fReaderThread >= 0) 154 return B_ERROR; // same as above 155 156 fReaderSem = create_sem(0, "pty_reader_sem"); 157 if (fReaderSem < 0) 158 return fReaderSem; 159 160 fReaderLocker = create_sem(0, "pty_locker_sem"); 161 if (fReaderLocker < 0) { 162 delete_sem(fReaderSem); 163 fReaderSem = -1; 164 return fReaderLocker; 165 } 166 167 fReaderThread = spawn_thread(_ptyreader_thread, "PtyReader", 168 B_NORMAL_PRIORITY, this); 169 if (fReaderThread < 0) { 170 delete_sem(fReaderSem); 171 fReaderSem = -1; 172 delete_sem(fReaderLocker); 173 fReaderLocker = -1; 174 return fReaderThread; 175 } 176 177 resume_thread(fReaderThread); 178 179 return B_OK; 180 } 181 182 183 void 184 TermParse::StopTermParse() 185 { 186 if (fParseThread >= 0) { 187 status_t dummy; 188 wait_for_thread(fParseThread, &dummy); 189 fParseThread = -1; 190 } 191 } 192 193 194 void 195 TermParse::StopPtyReader() 196 { 197 if (fReaderSem >= 0) { 198 delete_sem(fReaderSem); 199 fReaderSem = -1; 200 } 201 if (fReaderLocker >= 0) { 202 delete_sem(fReaderLocker); 203 fReaderLocker = -1; 204 } 205 206 if (fReaderThread >= 0) { 207 suspend_thread(fReaderThread); 208 209 status_t status; 210 wait_for_thread(fReaderThread, &status); 211 212 fReaderThread = -1; 213 } 214 } 215 216 217 //! Get data from pty device. 218 int32 219 TermParse::PtyReader() 220 { 221 int32 bufferSize = 0; 222 int32 readPos = 0; 223 while (!fQuitting) { 224 // If Pty Buffer nearly full, snooze this thread, and continue. 225 while (READ_BUF_SIZE - bufferSize < MIN_PTY_BUFFER_SPACE) { 226 status_t status; 227 do { 228 status = acquire_sem(fReaderLocker); 229 } while (status == B_INTERRUPTED); 230 if (status < B_OK) 231 return status; 232 233 bufferSize = fReadBufferSize; 234 } 235 236 // Read PTY 237 uchar buf[READ_BUF_SIZE]; 238 ssize_t nread = read(fFd, buf, READ_BUF_SIZE - bufferSize); 239 if (nread <= 0) { 240 fBuffer->NotifyQuit(errno); 241 return B_OK; 242 } 243 244 // Copy read string to PtyBuffer. 245 246 int32 left = READ_BUF_SIZE - readPos; 247 248 if (nread >= left) { 249 memcpy(fReadBuffer + readPos, buf, left); 250 memcpy(fReadBuffer, buf + left, nread - left); 251 } else 252 memcpy(fReadBuffer + readPos, buf, nread); 253 254 bufferSize = atomic_add(&fReadBufferSize, nread); 255 if (bufferSize == 0 && fParserWaiting) 256 release_sem(fReaderSem); 257 258 bufferSize += nread; 259 readPos = (readPos + nread) % READ_BUF_SIZE; 260 } 261 262 return B_OK; 263 } 264 265 266 void 267 TermParse::DumpState(int *groundtable, int *parsestate, uchar c) 268 { 269 static const struct { 270 int *p; 271 const char *name; 272 } tables[] = { 273 #define T(t) \ 274 { t, #t } 275 T(gUTF8GroundTable), 276 T(gCS96GroundTable), 277 T(gISO8859GroundTable), 278 T(gSJISGroundTable), 279 T(gEscTable), 280 T(gCsiTable), 281 T(gDecTable), 282 T(gScrTable), 283 T(gIgnoreTable), 284 T(gIesTable), 285 T(gEscIgnoreTable), 286 T(gMbcsTable), 287 { NULL, NULL } 288 }; 289 int i; 290 fprintf(stderr, "groundtable: "); 291 for (i = 0; tables[i].p; i++) 292 if (tables[i].p == groundtable) 293 fprintf(stderr, "%s\t", tables[i].name); 294 fprintf(stderr, "parsestate: "); 295 for (i = 0; tables[i].p; i++) 296 if (tables[i].p == parsestate) 297 fprintf(stderr, "%s\t", tables[i].name); 298 fprintf(stderr, "char: 0x%02x (%d)\n", c, c); 299 } 300 301 302 int32 303 TermParse::EscParse() 304 { 305 int tmp; 306 int top, bot; 307 int cs96 = 0; 308 uchar curess = 0; 309 310 char cbuf[4], dstbuf[4]; 311 char *ptr; 312 313 int now_coding = -1; 314 315 ushort attr = BACKCOLOR; 316 317 int param[NPARAM]; 318 int nparam = 1; 319 320 int row, col; 321 322 /* default coding system is UTF8 */ 323 int *groundtable = gUTF8GroundTable; 324 int *parsestate = groundtable; 325 326 int width = 1; 327 BAutolock locker(fBuffer); 328 329 while (!fQuitting) { 330 uchar c; 331 if (_NextParseChar(c) < B_OK) 332 break; 333 334 //DumpState(groundtable, parsestate, c); 335 336 if (now_coding != fBuffer->Encoding()) { 337 /* 338 * Change coding, change parse table. 339 */ 340 switch (fBuffer->Encoding()) { 341 case B_ISO1_CONVERSION: 342 case B_ISO2_CONVERSION: 343 case B_ISO3_CONVERSION: 344 case B_ISO4_CONVERSION: 345 case B_ISO5_CONVERSION: 346 case B_ISO6_CONVERSION: 347 case B_ISO7_CONVERSION: 348 case B_ISO8_CONVERSION: 349 case B_ISO9_CONVERSION: 350 case B_ISO10_CONVERSION: 351 groundtable = gISO8859GroundTable; 352 break; 353 case B_SJIS_CONVERSION: 354 groundtable = gSJISGroundTable; 355 break; 356 case B_EUC_CONVERSION: 357 case B_EUC_KR_CONVERSION: 358 case B_JIS_CONVERSION: 359 case B_GBK_CONVERSION: 360 case B_BIG5_CONVERSION: 361 groundtable = gISO8859GroundTable; 362 break; 363 case M_UTF8: 364 default: 365 groundtable = gUTF8GroundTable; 366 break; 367 } 368 parsestate = groundtable; 369 now_coding = fBuffer->Encoding(); 370 } 371 372 //debug_printf("TermParse: char: '%c' (%d), parse state: %d\n", c, c, parsestate[c]); 373 switch (parsestate[c]) { 374 case CASE_PRINT: 375 fBuffer->InsertChar((char)c, attr); 376 break; 377 378 case CASE_PRINT_GR: 379 /* case iso8859 gr character, or euc */ 380 ptr = cbuf; 381 if (now_coding == B_EUC_CONVERSION 382 || now_coding == B_EUC_KR_CONVERSION 383 || now_coding == B_JIS_CONVERSION 384 || now_coding == B_GBK_CONVERSION 385 || now_coding == B_BIG5_CONVERSION) { 386 switch (parsestate[curess]) { 387 case CASE_SS2: /* JIS X 0201 */ 388 width = 1; 389 *ptr++ = curess; 390 *ptr++ = c; 391 *ptr = 0; 392 curess = 0; 393 break; 394 395 case CASE_SS3: /* JIS X 0212 */ 396 width = 1; 397 *ptr++ = curess; 398 *ptr++ = c; 399 _NextParseChar(c); 400 *ptr++ = c; 401 *ptr = 0; 402 curess = 0; 403 break; 404 405 default: /* JIS X 0208 */ 406 width = 2; 407 *ptr++ = c; 408 _NextParseChar(c); 409 *ptr++ = c; 410 *ptr = 0; 411 break; 412 } 413 } else { 414 /* ISO-8859-1...10 and MacRoman */ 415 *ptr++ = c; 416 *ptr = 0; 417 } 418 419 if (now_coding != B_JIS_CONVERSION) { 420 CodeConv::ConvertToInternal(cbuf, -1, dstbuf, now_coding); 421 } else { 422 CodeConv::ConvertToInternal(cbuf, -1, dstbuf, 423 B_EUC_CONVERSION); 424 } 425 426 fBuffer->InsertChar(dstbuf, 4, width, attr); 427 break; 428 429 case CASE_PRINT_CS96: 430 cbuf[0] = c | 0x80; 431 _NextParseChar(c); 432 cbuf[1] = c | 0x80; 433 cbuf[2] = 0; 434 CodeConv::ConvertToInternal(cbuf, 2, dstbuf, B_EUC_CONVERSION); 435 fBuffer->InsertChar(dstbuf, 4, attr); 436 break; 437 438 case CASE_LF: 439 fBuffer->InsertLF(); 440 break; 441 442 case CASE_CR: 443 fBuffer->InsertCR(); 444 break; 445 446 case CASE_SJIS_KANA: 447 cbuf[0] = c; 448 cbuf[1] = '\0'; 449 CodeConv::ConvertToInternal(cbuf, 1, dstbuf, now_coding); 450 fBuffer->InsertChar(dstbuf, 4, attr); 451 break; 452 453 case CASE_SJIS_INSTRING: 454 cbuf[0] = c; 455 _NextParseChar(c); 456 cbuf[1] = c; 457 cbuf[2] = '\0'; 458 CodeConv::ConvertToInternal(cbuf, 2, dstbuf, now_coding); 459 fBuffer->InsertChar(dstbuf, 4, attr); 460 break; 461 462 case CASE_UTF8_2BYTE: 463 cbuf[0] = c; 464 _NextParseChar(c); 465 if (groundtable[c] != CASE_UTF8_INSTRING) 466 break; 467 cbuf[1] = c; 468 cbuf[2] = '\0'; 469 470 fBuffer->InsertChar(cbuf, 2, attr); 471 break; 472 473 case CASE_UTF8_3BYTE: 474 cbuf[0] = c; 475 _NextParseChar(c); 476 if (groundtable[c] != CASE_UTF8_INSTRING) 477 break; 478 cbuf[1] = c; 479 480 _NextParseChar(c); 481 if (groundtable[c] != CASE_UTF8_INSTRING) 482 break; 483 cbuf[2] = c; 484 cbuf[3] = '\0'; 485 fBuffer->InsertChar(cbuf, 3, attr); 486 break; 487 488 case CASE_MBCS: 489 /* ESC $ */ 490 parsestate = gMbcsTable; 491 break; 492 493 case CASE_GSETS: 494 /* ESC $ ? */ 495 parsestate = gCS96GroundTable; 496 cs96 = 1; 497 break; 498 499 case CASE_SCS_STATE: 500 { 501 cs96 = 0; 502 uchar dummy; 503 _NextParseChar(dummy); 504 parsestate = groundtable; 505 break; 506 } 507 case CASE_GROUND_STATE: 508 /* exit ignore mode */ 509 parsestate = groundtable; 510 break; 511 512 case CASE_BELL: 513 beep(); 514 break; 515 516 case CASE_BS: 517 fBuffer->MoveCursorLeft(1); 518 break; 519 520 case CASE_TAB: 521 tmp = fBuffer->Cursor().x; 522 tmp %= 8; 523 fBuffer->MoveCursorRight(8 - tmp); 524 break; 525 526 case CASE_ESC: 527 /* escape */ 528 parsestate = gEscTable; 529 break; 530 531 case CASE_IGNORE_STATE: 532 /* Ies: ignore anything else */ 533 parsestate = gIgnoreTable; 534 break; 535 536 case CASE_IGNORE_ESC: 537 /* Ign: escape */ 538 parsestate = gIesTable; 539 break; 540 541 case CASE_IGNORE: 542 /* Ignore character */ 543 break; 544 545 case CASE_SI: 546 break; 547 548 case CASE_SO: 549 break; 550 551 case CASE_SCR_STATE: // ESC # 552 /* enter scr state */ 553 parsestate = gScrTable; 554 break; 555 556 case CASE_ESC_IGNORE: 557 /* unknown escape sequence */ 558 parsestate = gEscIgnoreTable; 559 break; 560 561 case CASE_ESC_DIGIT: // ESC [ number 562 /* digit in csi or dec mode */ 563 if ((row = param[nparam - 1]) == DEFAULT) 564 row = 0; 565 param[nparam - 1] = 10 * row + (c - '0'); 566 break; 567 568 case CASE_ESC_SEMI: // ESC ; 569 /* semicolon in csi or dec mode */ 570 if (nparam < NPARAM) 571 param[nparam++] = DEFAULT; 572 break; 573 574 case CASE_DEC_STATE: 575 /* enter dec mode */ 576 parsestate = gDecTable; 577 break; 578 579 case CASE_ICH: // ESC [@ insert charactor 580 /* ICH */ 581 if ((row = param[0]) < 1) 582 row = 1; 583 fBuffer->InsertSpace(row); 584 parsestate = groundtable; 585 break; 586 587 case CASE_CUU: // ESC [A cursor up, up arrow key. 588 /* CUU */ 589 if ((row = param[0]) < 1) 590 row = 1; 591 fBuffer->MoveCursorUp(row); 592 parsestate = groundtable; 593 break; 594 595 case CASE_CUD: // ESC [B cursor down, down arrow key. 596 /* CUD */ 597 if ((row = param[0]) < 1) 598 row = 1; 599 fBuffer->MoveCursorDown(row); 600 parsestate = groundtable; 601 break; 602 603 case CASE_CUF: // ESC [C cursor forword 604 /* CUF */ 605 if ((row = param[0]) < 1) 606 row = 1; 607 fBuffer->MoveCursorRight(row); 608 parsestate = groundtable; 609 break; 610 611 case CASE_CUB: // ESC [D cursor backword 612 /* CUB */ 613 if ((row = param[0]) < 1) 614 row = 1; 615 fBuffer->MoveCursorLeft(row); 616 parsestate = groundtable; 617 break; 618 619 case CASE_CUP: // ESC [...H move cursor 620 /* CUP | HVP */ 621 if ((row = param[0]) < 1) 622 row = 1; 623 if (nparam < 2 || (col = param[1]) < 1) 624 col = 1; 625 626 fBuffer->SetCursor(col - 1, row - 1 ); 627 parsestate = groundtable; 628 break; 629 630 case CASE_ED: // ESC [ ...J clear screen 631 /* ED */ 632 switch (param[0]) { 633 case DEFAULT: 634 case 0: 635 fBuffer->EraseBelow(); 636 break; 637 638 case 1: 639 fBuffer->EraseAbove(); 640 break; 641 642 case 2: 643 fBuffer->EraseAll(); 644 break; 645 } 646 parsestate = groundtable; 647 break; 648 649 case CASE_EL: // delete line 650 /* EL */ 651 fBuffer->DeleteColumns(); 652 parsestate = groundtable; 653 break; 654 655 case CASE_IL: 656 /* IL */ 657 if ((row = param[0]) < 1) 658 row = 1; 659 fBuffer->InsertLines(row); 660 parsestate = groundtable; 661 break; 662 663 case CASE_DL: 664 /* DL */ 665 if ((row = param[0]) < 1) 666 row = 1; 667 fBuffer->DeleteLines(row); 668 parsestate = groundtable; 669 break; 670 671 case CASE_DCH: 672 /* DCH */ 673 if ((row = param[0]) < 1) 674 row = 1; 675 fBuffer->DeleteChars(row); 676 parsestate = groundtable; 677 break; 678 679 case CASE_SET: 680 /* SET */ 681 if (param[0] == 4) 682 fBuffer->SetInsertMode(MODE_INSERT); 683 parsestate = groundtable; 684 break; 685 686 case CASE_RST: 687 /* RST */ 688 if (param[0] == 4) 689 fBuffer->SetInsertMode(MODE_OVER); 690 parsestate = groundtable; 691 break; 692 693 case CASE_SGR: 694 /* SGR */ 695 for (row = 0; row < nparam; ++row) { 696 switch (param[row]) { 697 case DEFAULT: 698 case 0: /* Reset attribute */ 699 attr = 0; 700 break; 701 702 case 1: 703 case 5: /* Bold */ 704 attr |= BOLD; 705 break; 706 707 case 4: /* Underline */ 708 attr |= UNDERLINE; 709 break; 710 711 case 7: /* Inverse */ 712 attr |= INVERSE; 713 break; 714 715 case 22: /* Not Bold */ 716 attr &= ~BOLD; 717 break; 718 719 case 24: /* Not Underline */ 720 attr &= ~UNDERLINE; 721 break; 722 723 case 27: /* Not Inverse */ 724 attr &= ~INVERSE; 725 break; 726 727 case 30: 728 case 31: 729 case 32: 730 case 33: 731 case 34: 732 case 35: 733 case 36: 734 case 37: 735 attr &= ~FORECOLOR; 736 attr |= FORECOLORED(param[row] - 30); 737 attr |= FORESET; 738 break; 739 740 case 39: 741 attr &= ~FORESET; 742 break; 743 744 case 40: 745 case 41: 746 case 42: 747 case 43: 748 case 44: 749 case 45: 750 case 46: 751 case 47: 752 attr &= ~BACKCOLOR; 753 attr |= BACKCOLORED(param[row] - 40); 754 attr |= BACKSET; 755 break; 756 757 case 49: 758 attr &= ~BACKSET; 759 break; 760 } 761 } 762 parsestate = groundtable; 763 break; 764 765 case CASE_CPR: 766 // Q & D hack by Y.Hayakawa (hida@sawada.riec.tohoku.ac.jp) 767 // 21-JUL-99 768 _DeviceStatusReport(param[0]); 769 parsestate = groundtable; 770 break; 771 772 case CASE_DECSTBM: 773 /* DECSTBM - set scrolling region */ 774 775 if ((top = param[0]) < 1) 776 top = 1; 777 778 if (nparam < 2) 779 bot = fBuffer->Height(); 780 else 781 bot = param[1]; 782 783 top--; 784 bot--; 785 786 if (bot > top) 787 fBuffer->SetScrollRegion(top, bot); 788 789 parsestate = groundtable; 790 break; 791 792 case CASE_DECREQTPARM: 793 parsestate = groundtable; 794 break; 795 796 case CASE_DECSET: 797 /* DECSET */ 798 for (int i = 0; i < nparam; i++) 799 _DecPrivateModeSet(param[i]); 800 parsestate = groundtable; 801 break; 802 803 case CASE_DECRST: 804 /* DECRST */ 805 for (int i = 0; i < nparam; i++) 806 _DecPrivateModeReset(param[i]); 807 parsestate = groundtable; 808 break; 809 810 case CASE_DECALN: 811 /* DECALN */ 812 // if(screen->cursor_state) 813 // HideCursor(); 814 // ScrnRefresh(screen, 0, 0, screen->max_row + 1, 815 // screen->max_col + 1, False); 816 parsestate = groundtable; 817 break; 818 819 // case CASE_GSETS: 820 // screen->gsets[scstype] = GSET(c) | cs96; 821 // parsestate = groundtable; 822 // break; 823 824 case CASE_DECSC: 825 /* DECSC */ 826 fBuffer->SaveCursor(); 827 parsestate = groundtable; 828 break; 829 830 case CASE_DECRC: 831 /* DECRC */ 832 fBuffer->RestoreCursor(); 833 parsestate = groundtable; 834 break; 835 836 case CASE_HTS: 837 /* HTS */ 838 // TabSet(term->tabs, screen->cur_col); 839 parsestate = groundtable; 840 break; 841 842 case CASE_RI: 843 /* RI */ 844 if (fBuffer->Cursor().y == 0) 845 fBuffer->ScrollBy(-1); 846 else 847 fBuffer->MoveCursorUp(1); 848 parsestate = groundtable; 849 break; 850 851 case CASE_SS2: 852 /* SS2 */ 853 curess = c; 854 parsestate = groundtable; 855 break; 856 857 case CASE_SS3: 858 /* SS3 */ 859 curess = c; 860 parsestate = groundtable; 861 break; 862 863 case CASE_CSI_STATE: 864 /* enter csi state */ 865 nparam = 1; 866 param[0] = DEFAULT; 867 parsestate = gCsiTable; 868 break; 869 870 case CASE_OSC: 871 { 872 /* Operating System Command: ESC ] */ 873 char string[512]; 874 uint32 len = 0; 875 uchar mode_char; 876 _NextParseChar(mode_char); 877 if (mode_char != '0' 878 && mode_char != '1' 879 && mode_char != '2') { 880 parsestate = groundtable; 881 break; 882 } 883 uchar current_char; 884 _NextParseChar(current_char); 885 while (_NextParseChar(current_char) == B_OK 886 && current_char != 0x7) { 887 if (!isprint(current_char & 0x7f) 888 || len+2 >= sizeof(string)) 889 break; 890 string[len++] = current_char; 891 } 892 if (current_char == 0x7) { 893 string[len] = '\0'; 894 switch (mode_char) { 895 case '0': 896 case '2': 897 fBuffer->SetTitle(string); 898 break; 899 case '1': 900 break; 901 } 902 } 903 parsestate = groundtable; 904 break; 905 } 906 907 case CASE_RIS: // ESC c ... Reset terminal. 908 break; 909 910 case CASE_LS2: 911 /* LS2 */ 912 // screen->curgl = 2; 913 parsestate = groundtable; 914 break; 915 916 case CASE_LS3: 917 /* LS3 */ 918 // screen->curgl = 3; 919 parsestate = groundtable; 920 break; 921 922 case CASE_LS3R: 923 /* LS3R */ 924 // screen->curgr = 3; 925 parsestate = groundtable; 926 break; 927 928 case CASE_LS2R: 929 /* LS2R */ 930 // screen->curgr = 2; 931 parsestate = groundtable; 932 break; 933 934 case CASE_LS1R: 935 /* LS1R */ 936 // screen->curgr = 1; 937 parsestate = groundtable; 938 break; 939 940 case CASE_VPA: // ESC [...d move cursor absolute vertical 941 /* VPA (CV) */ 942 if ((row = param[0]) < 1) 943 row = 1; 944 945 // note beterm wants it 1-based unlike usual terminals 946 fBuffer->SetCursorY(row - 1); 947 parsestate = groundtable; 948 break; 949 950 case CASE_HPA: // ESC [...G move cursor absolute horizontal 951 /* HPA (CH) */ 952 if ((col = param[0]) < 1) 953 col = 1; 954 955 // note beterm wants it 1-based unlike usual terminals 956 fBuffer->SetCursorX(col - 1); 957 parsestate = groundtable; 958 break; 959 960 case CASE_SU: // scroll screen up 961 if ((row = param[0]) < 1) 962 row = 1; 963 fBuffer->ScrollBy(row); 964 parsestate = groundtable; 965 break; 966 967 case CASE_SD: // scroll screen down 968 if ((row = param[0]) < 1) 969 row = 1; 970 fBuffer->ScrollBy(-row); 971 parsestate = groundtable; 972 break; 973 974 975 case CASE_ECH: // erase characters 976 if ((col = param[0]) < 1) 977 col = 1; 978 fBuffer->EraseChars(col); 979 parsestate = groundtable; 980 break; 981 982 default: 983 break; 984 } 985 } 986 987 return B_OK; 988 } 989 990 991 /*static*/ int32 992 TermParse::_ptyreader_thread(void *data) 993 { 994 return reinterpret_cast<TermParse *>(data)->PtyReader(); 995 } 996 997 998 /*static*/ int32 999 TermParse::_escparse_thread(void *data) 1000 { 1001 return reinterpret_cast<TermParse *>(data)->EscParse(); 1002 } 1003 1004 1005 status_t 1006 TermParse::_ReadParserBuffer() 1007 { 1008 // We have to unlock the terminal buffer while waiting for data from the 1009 // PTY. We don't have to unlock when we don't need to wait, but we do it 1010 // anyway, so that TermView won't be starved when trying to synchronize. 1011 fBuffer->Unlock(); 1012 1013 // wait for new input from pty 1014 if (fReadBufferSize == 0) { 1015 fParserWaiting = true; 1016 1017 status_t status = B_OK; 1018 while (fReadBufferSize == 0 && status == B_OK) { 1019 do { 1020 status = acquire_sem(fReaderSem); 1021 } while (status == B_INTERRUPTED); 1022 } 1023 1024 fParserWaiting = false; 1025 1026 if (status < B_OK) { 1027 fBuffer->Lock(); 1028 return status; 1029 } 1030 } 1031 1032 int32 toRead = fReadBufferSize; 1033 if (toRead > ESC_PARSER_BUFFER_SIZE) 1034 toRead = ESC_PARSER_BUFFER_SIZE; 1035 1036 for (int32 i = 0; i < toRead; i++) { 1037 fParserBuffer[i] = fReadBuffer[fBufferPosition]; 1038 fBufferPosition = (fBufferPosition + 1) % READ_BUF_SIZE; 1039 } 1040 1041 int32 bufferSize = atomic_add(&fReadBufferSize, -toRead); 1042 1043 // If the pty reader thread waits and we have made enough space in the 1044 // buffer now, let it run again. 1045 if (bufferSize > READ_BUF_SIZE - MIN_PTY_BUFFER_SPACE 1046 && bufferSize - toRead <= READ_BUF_SIZE - MIN_PTY_BUFFER_SPACE) { 1047 release_sem(fReaderLocker); 1048 } 1049 1050 fParserBufferSize = toRead; 1051 fParserBufferOffset = 0; 1052 1053 fBuffer->Lock(); 1054 return B_OK; 1055 } 1056 1057 1058 void 1059 TermParse::_DeviceStatusReport(int n) 1060 { 1061 char sbuf[16] ; 1062 int len; 1063 1064 switch (n) { 1065 case 5: 1066 { 1067 const char* toWrite = "\033[0n"; 1068 write(fFd, toWrite, strlen(toWrite)); 1069 break ; 1070 } 1071 case 6: 1072 len = sprintf(sbuf, "\033[%ld;%ldR", fBuffer->Height(), 1073 fBuffer->Width()) ; 1074 write(fFd, sbuf, len); 1075 break ; 1076 default: 1077 return; 1078 } 1079 } 1080 1081 1082 void 1083 TermParse::_DecPrivateModeSet(int value) 1084 { 1085 switch (value) { 1086 case 1: 1087 // Application Cursor Keys (whatever that means). 1088 // Not supported yet. 1089 break; 1090 case 5: 1091 // Reverse Video (inverses colors for the complete screen 1092 // -- when followed by normal video, that's shortly flashes the 1093 // screen). 1094 // Not supported yet. 1095 break; 1096 case 9: 1097 // Set Mouse X and Y on button press. 1098 fBuffer->ReportX10MouseEvent(true); 1099 break; 1100 case 12: 1101 // Start Blinking Cursor. 1102 // Not supported yet. 1103 break; 1104 case 25: 1105 // Show Cursor. 1106 // Not supported yet. 1107 break; 1108 case 47: 1109 // Use Alternate Screen Buffer. 1110 fBuffer->UseAlternateScreenBuffer(false); 1111 break; 1112 case 1000: 1113 // Send Mouse X & Y on button press and release. 1114 fBuffer->ReportNormalMouseEvent(true); 1115 break; 1116 case 1002: 1117 // Send Mouse X and Y on button press and release, and on motion 1118 // when the mouse enter a new cell 1119 fBuffer->ReportButtonMouseEvent(true); 1120 break; 1121 case 1003: 1122 // Use All Motion Mouse Tracking 1123 fBuffer->ReportAnyMouseEvent(true); 1124 break; 1125 case 1034: 1126 // TODO: Interprete "meta" key, sets eighth bit. 1127 // Not supported yet. 1128 break; 1129 case 1036: 1130 // TODO: Send ESC when Meta modifies a key 1131 // Not supported yet. 1132 break; 1133 case 1039: 1134 // TODO: Send ESC when Alt modifies a key 1135 // Not supported yet. 1136 break; 1137 case 1049: 1138 // Save cursor as in DECSC and use Alternate Screen Buffer, clearing 1139 // it first. 1140 fBuffer->SaveCursor(); 1141 fBuffer->UseAlternateScreenBuffer(true); 1142 break; 1143 } 1144 } 1145 1146 1147 void 1148 TermParse::_DecPrivateModeReset(int value) 1149 { 1150 switch (value) { 1151 case 1: 1152 // Normal Cursor Keys (whatever that means). 1153 // Not supported yet. 1154 break; 1155 case 3: 1156 // 80 Column Mode. 1157 // Not supported yet. 1158 break; 1159 case 4: 1160 // Jump (Fast) Scroll. 1161 // Not supported yet. 1162 break; 1163 case 5: 1164 // Normal Video (Leaves Reverse Video, cf. there). 1165 // Not supported yet. 1166 break; 1167 case 9: 1168 // Disable Mouse X and Y on button press. 1169 fBuffer->ReportX10MouseEvent(false); 1170 break; 1171 case 12: 1172 // Stop Blinking Cursor. 1173 // Not supported yet. 1174 break; 1175 case 25: 1176 // Hide Cursor 1177 // Not supported yet. 1178 break; 1179 case 47: 1180 // Use Normal Screen Buffer. 1181 fBuffer->UseNormalScreenBuffer(); 1182 break; 1183 case 1000: 1184 // Don't send Mouse X & Y on button press and release. 1185 fBuffer->ReportNormalMouseEvent(false); 1186 break; 1187 case 1002: 1188 // Don't send Mouse X and Y on button press and release, and on motion 1189 // when the mouse enter a new cell 1190 fBuffer->ReportButtonMouseEvent(false); 1191 break; 1192 case 1003: 1193 // Disable All Motion Mouse Tracking. 1194 fBuffer->ReportAnyMouseEvent(false); 1195 break; 1196 case 1034: 1197 // Don't interprete "meta" key. 1198 // Not supported yet. 1199 break; 1200 case 1036: 1201 // TODO: Don't send ESC when Meta modifies a key 1202 // Not supported yet. 1203 break; 1204 case 1039: 1205 // TODO: Don't send ESC when Alt modifies a key 1206 // Not supported yet. 1207 break; 1208 case 1049: 1209 // Use Normal Screen Buffer and restore cursor as in DECRC. 1210 fBuffer->UseNormalScreenBuffer(); 1211 fBuffer->RestoreCursor(); 1212 break; 1213 } 1214 } 1215