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