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->EraseBelow(); 644 fBuffer->EraseAbove(); 645 break; 646 } 647 parsestate = groundtable; 648 break; 649 650 case CASE_EL: // delete line 651 /* EL */ 652 fBuffer->DeleteColumns(); 653 parsestate = groundtable; 654 break; 655 656 case CASE_IL: 657 /* IL */ 658 if ((row = param[0]) < 1) 659 row = 1; 660 fBuffer->InsertLines(row); 661 parsestate = groundtable; 662 break; 663 664 case CASE_DL: 665 /* DL */ 666 if ((row = param[0]) < 1) 667 row = 1; 668 fBuffer->DeleteLines(row); 669 parsestate = groundtable; 670 break; 671 672 case CASE_DCH: 673 /* DCH */ 674 if ((row = param[0]) < 1) 675 row = 1; 676 fBuffer->DeleteChars(row); 677 parsestate = groundtable; 678 break; 679 680 case CASE_SET: 681 /* SET */ 682 if (param[0] == 4) 683 fBuffer->SetInsertMode(MODE_INSERT); 684 parsestate = groundtable; 685 break; 686 687 case CASE_RST: 688 /* RST */ 689 if (param[0] == 4) 690 fBuffer->SetInsertMode(MODE_OVER); 691 parsestate = groundtable; 692 break; 693 694 case CASE_SGR: 695 /* SGR */ 696 for (row = 0; row < nparam; ++row) { 697 switch (param[row]) { 698 case DEFAULT: 699 case 0: /* Reset attribute */ 700 attr = 0; 701 break; 702 703 case 1: 704 case 5: /* Bold */ 705 attr |= BOLD; 706 break; 707 708 case 4: /* Underline */ 709 attr |= UNDERLINE; 710 break; 711 712 case 7: /* Inverse */ 713 attr |= INVERSE; 714 break; 715 716 case 22: /* Not Bold */ 717 attr &= ~BOLD; 718 break; 719 720 case 24: /* Not Underline */ 721 attr &= ~UNDERLINE; 722 break; 723 724 case 27: /* Not Inverse */ 725 attr &= ~INVERSE; 726 break; 727 728 case 30: 729 case 31: 730 case 32: 731 case 33: 732 case 34: 733 case 35: 734 case 36: 735 case 37: 736 attr &= ~FORECOLOR; 737 attr |= FORECOLORED(param[row] - 30); 738 attr |= FORESET; 739 break; 740 741 case 39: 742 attr &= ~FORESET; 743 break; 744 745 case 40: 746 case 41: 747 case 42: 748 case 43: 749 case 44: 750 case 45: 751 case 46: 752 case 47: 753 attr &= ~BACKCOLOR; 754 attr |= BACKCOLORED(param[row] - 40); 755 attr |= BACKSET; 756 break; 757 758 case 49: 759 attr &= ~BACKSET; 760 break; 761 } 762 } 763 parsestate = groundtable; 764 break; 765 766 case CASE_CPR: 767 // Q & D hack by Y.Hayakawa (hida@sawada.riec.tohoku.ac.jp) 768 // 21-JUL-99 769 _DeviceStatusReport(param[0]); 770 parsestate = groundtable; 771 break; 772 773 case CASE_DECSTBM: 774 /* DECSTBM - set scrolling region */ 775 776 if ((top = param[0]) < 1) 777 top = 1; 778 779 if (nparam < 2) 780 bot = fBuffer->Height(); 781 else 782 bot = param[1]; 783 784 top--; 785 bot--; 786 787 if (bot > top) 788 fBuffer->SetScrollRegion(top, bot); 789 790 parsestate = groundtable; 791 break; 792 793 case CASE_DECREQTPARM: 794 parsestate = groundtable; 795 break; 796 797 case CASE_DECSET: 798 /* DECSET */ 799 for (int i = 0; i < nparam; i++) 800 _DecPrivateModeSet(param[i]); 801 parsestate = groundtable; 802 break; 803 804 case CASE_DECRST: 805 /* DECRST */ 806 for (int i = 0; i < nparam; i++) 807 _DecPrivateModeReset(param[i]); 808 parsestate = groundtable; 809 break; 810 811 case CASE_DECALN: 812 /* DECALN */ 813 // if(screen->cursor_state) 814 // HideCursor(); 815 // ScrnRefresh(screen, 0, 0, screen->max_row + 1, 816 // screen->max_col + 1, False); 817 parsestate = groundtable; 818 break; 819 820 // case CASE_GSETS: 821 // screen->gsets[scstype] = GSET(c) | cs96; 822 // parsestate = groundtable; 823 // break; 824 825 case CASE_DECSC: 826 /* DECSC */ 827 fBuffer->SaveCursor(); 828 parsestate = groundtable; 829 break; 830 831 case CASE_DECRC: 832 /* DECRC */ 833 fBuffer->RestoreCursor(); 834 parsestate = groundtable; 835 break; 836 837 case CASE_HTS: 838 /* HTS */ 839 // TabSet(term->tabs, screen->cur_col); 840 parsestate = groundtable; 841 break; 842 843 case CASE_RI: 844 /* RI */ 845 if (fBuffer->Cursor().y == 0) 846 fBuffer->ScrollBy(-1); 847 else 848 fBuffer->MoveCursorUp(1); 849 parsestate = groundtable; 850 break; 851 852 case CASE_SS2: 853 /* SS2 */ 854 curess = c; 855 parsestate = groundtable; 856 break; 857 858 case CASE_SS3: 859 /* SS3 */ 860 curess = c; 861 parsestate = groundtable; 862 break; 863 864 case CASE_CSI_STATE: 865 /* enter csi state */ 866 nparam = 1; 867 param[0] = DEFAULT; 868 parsestate = gCsiTable; 869 break; 870 871 case CASE_OSC: 872 { 873 /* Operating System Command: ESC ] */ 874 char string[512]; 875 uint32 len = 0; 876 uchar mode_char; 877 _NextParseChar(mode_char); 878 if (mode_char != '0' 879 && mode_char != '1' 880 && mode_char != '2') { 881 parsestate = groundtable; 882 break; 883 } 884 uchar current_char; 885 _NextParseChar(current_char); 886 while (_NextParseChar(current_char) == B_OK 887 && current_char != 0x7) { 888 if (!isprint(current_char & 0x7f) 889 || len+2 >= sizeof(string)) 890 break; 891 string[len++] = current_char; 892 } 893 if (current_char == 0x7) { 894 string[len] = '\0'; 895 switch (mode_char) { 896 case '0': 897 case '2': 898 fBuffer->SetTitle(string); 899 break; 900 case '1': 901 break; 902 } 903 } 904 parsestate = groundtable; 905 break; 906 } 907 908 case CASE_RIS: // ESC c ... Reset terminal. 909 break; 910 911 case CASE_LS2: 912 /* LS2 */ 913 // screen->curgl = 2; 914 parsestate = groundtable; 915 break; 916 917 case CASE_LS3: 918 /* LS3 */ 919 // screen->curgl = 3; 920 parsestate = groundtable; 921 break; 922 923 case CASE_LS3R: 924 /* LS3R */ 925 // screen->curgr = 3; 926 parsestate = groundtable; 927 break; 928 929 case CASE_LS2R: 930 /* LS2R */ 931 // screen->curgr = 2; 932 parsestate = groundtable; 933 break; 934 935 case CASE_LS1R: 936 /* LS1R */ 937 // screen->curgr = 1; 938 parsestate = groundtable; 939 break; 940 941 case CASE_VPA: // ESC [...d move cursor absolute vertical 942 /* VPA (CV) */ 943 if ((row = param[0]) < 1) 944 row = 1; 945 946 // note beterm wants it 1-based unlike usual terminals 947 fBuffer->SetCursorY(row - 1); 948 parsestate = groundtable; 949 break; 950 951 case CASE_HPA: // ESC [...G move cursor absolute horizontal 952 /* HPA (CH) */ 953 if ((col = param[0]) < 1) 954 col = 1; 955 956 // note beterm wants it 1-based unlike usual terminals 957 fBuffer->SetCursorX(col - 1); 958 parsestate = groundtable; 959 break; 960 961 case CASE_SU: // scroll screen up 962 if ((row = param[0]) < 1) 963 row = 1; 964 fBuffer->ScrollBy(row); 965 parsestate = groundtable; 966 break; 967 968 case CASE_SD: // scroll screen down 969 if ((row = param[0]) < 1) 970 row = 1; 971 fBuffer->ScrollBy(-row); 972 parsestate = groundtable; 973 break; 974 975 976 case CASE_ECH: // erase characters 977 if ((col = param[0]) < 1) 978 col = 1; 979 fBuffer->EraseChars(col); 980 parsestate = groundtable; 981 break; 982 983 default: 984 break; 985 } 986 } 987 988 return B_OK; 989 } 990 991 992 /*static*/ int32 993 TermParse::_ptyreader_thread(void *data) 994 { 995 return reinterpret_cast<TermParse *>(data)->PtyReader(); 996 } 997 998 999 /*static*/ int32 1000 TermParse::_escparse_thread(void *data) 1001 { 1002 return reinterpret_cast<TermParse *>(data)->EscParse(); 1003 } 1004 1005 1006 status_t 1007 TermParse::_ReadParserBuffer() 1008 { 1009 // We have to unlock the terminal buffer while waiting for data from the 1010 // PTY. We don't have to unlock when we don't need to wait, but we do it 1011 // anyway, so that TermView won't be starved when trying to synchronize. 1012 fBuffer->Unlock(); 1013 1014 // wait for new input from pty 1015 if (fReadBufferSize == 0) { 1016 fParserWaiting = true; 1017 1018 status_t status = B_OK; 1019 while (fReadBufferSize == 0 && status == B_OK) { 1020 do { 1021 status = acquire_sem(fReaderSem); 1022 } while (status == B_INTERRUPTED); 1023 } 1024 1025 fParserWaiting = false; 1026 1027 if (status < B_OK) { 1028 fBuffer->Lock(); 1029 return status; 1030 } 1031 } 1032 1033 int32 toRead = fReadBufferSize; 1034 if (toRead > ESC_PARSER_BUFFER_SIZE) 1035 toRead = ESC_PARSER_BUFFER_SIZE; 1036 1037 for (int32 i = 0; i < toRead; i++) { 1038 fParserBuffer[i] = fReadBuffer[fBufferPosition]; 1039 fBufferPosition = (fBufferPosition + 1) % READ_BUF_SIZE; 1040 } 1041 1042 int32 bufferSize = atomic_add(&fReadBufferSize, -toRead); 1043 1044 // If the pty reader thread waits and we have made enough space in the 1045 // buffer now, let it run again. 1046 if (bufferSize > READ_BUF_SIZE - MIN_PTY_BUFFER_SPACE 1047 && bufferSize - toRead <= READ_BUF_SIZE - MIN_PTY_BUFFER_SPACE) { 1048 release_sem(fReaderLocker); 1049 } 1050 1051 fParserBufferSize = toRead; 1052 fParserBufferOffset = 0; 1053 1054 fBuffer->Lock(); 1055 return B_OK; 1056 } 1057 1058 1059 void 1060 TermParse::_DeviceStatusReport(int n) 1061 { 1062 char sbuf[16] ; 1063 int len; 1064 1065 switch (n) { 1066 case 5: 1067 { 1068 const char* toWrite = "\033[0n"; 1069 write(fFd, toWrite, strlen(toWrite)); 1070 break ; 1071 } 1072 case 6: 1073 len = sprintf(sbuf, "\033[%ld;%ldR", fBuffer->Height(), 1074 fBuffer->Width()) ; 1075 write(fFd, sbuf, len); 1076 break ; 1077 default: 1078 return; 1079 } 1080 } 1081 1082 1083 void 1084 TermParse::_DecPrivateModeSet(int value) 1085 { 1086 switch (value) { 1087 case 1: 1088 // Application Cursor Keys (whatever that means). 1089 // Not supported yet. 1090 break; 1091 case 5: 1092 // Reverse Video (inverses colors for the complete screen 1093 // -- when followed by normal video, that's shortly flashes the 1094 // screen). 1095 // Not supported yet. 1096 break; 1097 case 9: 1098 // Set Mouse X and Y on button press. 1099 fBuffer->ReportX10MouseEvent(true); 1100 break; 1101 case 12: 1102 // Start Blinking Cursor. 1103 // Not supported yet. 1104 break; 1105 case 25: 1106 // Show Cursor. 1107 // Not supported yet. 1108 break; 1109 case 47: 1110 // Use Alternate Screen Buffer. 1111 fBuffer->UseAlternateScreenBuffer(false); 1112 break; 1113 case 1000: 1114 // Send Mouse X & Y on button press and release. 1115 fBuffer->ReportNormalMouseEvent(true); 1116 break; 1117 case 1002: 1118 // Send Mouse X and Y on button press and release, and on motion 1119 // when the mouse enter a new cell 1120 fBuffer->ReportButtonMouseEvent(true); 1121 break; 1122 case 1003: 1123 // Use All Motion Mouse Tracking 1124 fBuffer->ReportAnyMouseEvent(true); 1125 break; 1126 case 1034: 1127 // TODO: Interprete "meta" key, sets eighth bit. 1128 // Not supported yet. 1129 break; 1130 case 1036: 1131 // TODO: Send ESC when Meta modifies a key 1132 // Not supported yet. 1133 break; 1134 case 1039: 1135 // TODO: Send ESC when Alt modifies a key 1136 // Not supported yet. 1137 break; 1138 case 1049: 1139 // Save cursor as in DECSC and use Alternate Screen Buffer, clearing 1140 // it first. 1141 fBuffer->SaveCursor(); 1142 fBuffer->UseAlternateScreenBuffer(true); 1143 break; 1144 } 1145 } 1146 1147 1148 void 1149 TermParse::_DecPrivateModeReset(int value) 1150 { 1151 switch (value) { 1152 case 1: 1153 // Normal Cursor Keys (whatever that means). 1154 // Not supported yet. 1155 break; 1156 case 3: 1157 // 80 Column Mode. 1158 // Not supported yet. 1159 break; 1160 case 4: 1161 // Jump (Fast) Scroll. 1162 // Not supported yet. 1163 break; 1164 case 5: 1165 // Normal Video (Leaves Reverse Video, cf. there). 1166 // Not supported yet. 1167 break; 1168 case 9: 1169 // Disable Mouse X and Y on button press. 1170 fBuffer->ReportX10MouseEvent(false); 1171 break; 1172 case 12: 1173 // Stop Blinking Cursor. 1174 // Not supported yet. 1175 break; 1176 case 25: 1177 // Hide Cursor 1178 // Not supported yet. 1179 break; 1180 case 47: 1181 // Use Normal Screen Buffer. 1182 fBuffer->UseNormalScreenBuffer(); 1183 break; 1184 case 1000: 1185 // Don't send Mouse X & Y on button press and release. 1186 fBuffer->ReportNormalMouseEvent(false); 1187 break; 1188 case 1002: 1189 // Don't send Mouse X and Y on button press and release, and on motion 1190 // when the mouse enter a new cell 1191 fBuffer->ReportButtonMouseEvent(false); 1192 break; 1193 case 1003: 1194 // Disable All Motion Mouse Tracking. 1195 fBuffer->ReportAnyMouseEvent(false); 1196 break; 1197 case 1034: 1198 // Don't interprete "meta" key. 1199 // Not supported yet. 1200 break; 1201 case 1036: 1202 // TODO: Don't send ESC when Meta modifies a key 1203 // Not supported yet. 1204 break; 1205 case 1039: 1206 // TODO: Don't send ESC when Alt modifies a key 1207 // Not supported yet. 1208 break; 1209 case 1049: 1210 // Use Normal Screen Buffer and restore cursor as in DECRC. 1211 fBuffer->UseNormalScreenBuffer(); 1212 fBuffer->RestoreCursor(); 1213 break; 1214 } 1215 } 1216