1 /* 2 * Copyright (c) 2001-2005, 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 9 #include <errno.h> 10 #include <stdio.h> 11 #include <signal.h> 12 #include <unistd.h> 13 14 #include <app/Application.h> 15 #include <support/Beep.h> 16 #include <Message.h> 17 #include <MessageRunner.h> 18 19 20 #include "TermParse.h" 21 #include "TermView.h" 22 #include "VTparse.h" 23 #include "TermConst.h" 24 #include "CodeConv.h" 25 26 extern int pfd; // defined Muterminal.cpp 27 28 ///////////////////////////////////////////////////////////////////////////// 29 // PtyReader ... Get character from pty device. 30 // 31 ///////////////////////////////////////////////////////////////////////////// 32 int32 33 TermParse::PtyReader(void *data) 34 { 35 int nread; 36 uint read_p = 0; 37 38 TermParse *theObj = (TermParse *) data; 39 40 uchar buf [READ_BUF_SIZE]; 41 42 while (theObj->fQuitting) { 43 /* 44 * If Pty Buffer nearly full, snooze this thread, and continue. 45 */ 46 if ((read_p - theObj->fParser_p) > READ_BUF_SIZE - 16) { 47 theObj->fLockFlag = READ_BUF_SIZE / 2; 48 acquire_sem (theObj->fReaderLocker); 49 } 50 51 /* 52 * Read PTY. 53 */ 54 nread = read (pfd, buf, 55 READ_BUF_SIZE - (read_p - theObj->fParser_p)); 56 if (nread <= 0) { 57 be_app->PostMessage(B_QUIT_REQUESTED); 58 exit_thread (B_ERROR); 59 60 } 61 62 63 int left = READ_BUF_SIZE - (read_p % READ_BUF_SIZE); 64 int mod = read_p % READ_BUF_SIZE; 65 66 /* 67 * Copy read string to PtyBuffer. 68 */ 69 if (nread >= left) { 70 memcpy (theObj->fReadBuf + mod, buf, left); 71 memcpy (theObj->fReadBuf, buf + left, nread - left); 72 } 73 else { 74 memcpy (theObj->fReadBuf + mod, buf, nread); 75 } 76 read_p += nread; 77 78 /* 79 * Release semaphore. Number of semaphore counter is nread. 80 */ 81 release_sem_etc (theObj->fReaderSem, nread, 0); 82 83 } 84 theObj->fReaderThread = -1; 85 exit_thread (B_OK); 86 return B_OK; 87 } 88 /////////////////////////////////////////////////////////////////////////// 89 // GetReaderBuf ... Get char pty reader buffer. 90 // 91 /////////////////////////////////////////////////////////////////////////// 92 93 uchar 94 TermParse::GetReaderBuf (void) 95 { 96 int c; 97 98 switch (acquire_sem_etc (fReaderSem, 1, B_TIMEOUT, (bigtime_t)10000.0)) { 99 case B_NO_ERROR: 100 break; 101 case B_TIMED_OUT: 102 default: 103 fViewObj->ScrollAtCursor(); 104 fViewObj->UpdateLine(); 105 106 // Reset cursor blinking time and turn on cursor blinking. 107 fCursorUpdate->SetInterval (1000000); 108 fViewObj->SetCurDraw (CURON); 109 110 // wait new input from pty. 111 acquire_sem (fReaderSem); 112 break; 113 } 114 115 c = fReadBuf[fParser_p % READ_BUF_SIZE]; 116 fParser_p++; 117 /* 118 * If PtyReader thread locked, decliment counter and unlock thread. 119 */ 120 if (fLockFlag != 0) { 121 fLockFlag--; 122 if (fLockFlag == 0) { 123 release_sem (fReaderLocker); 124 } 125 } 126 127 fViewObj->SetCurDraw (CUROFF); 128 129 return c; 130 } 131 132 /////////////////////////////////////////////////////////////////////////// 133 // InitTermParse ... Initialize and spawn EscParse thread. 134 // 135 /////////////////////////////////////////////////////////////////////////// 136 status_t 137 TermParse::InitTermParse (TermView *inViewObj, CodeConv *inConvObj) 138 { 139 140 fViewObj = inViewObj; 141 fConvObj = inConvObj; 142 143 fCursorUpdate = new BMessageRunner (BMessenger (fViewObj), 144 new BMessage (MSGRUN_CURSOR), 145 1000000); 146 147 if (fParseThread < 0) 148 fParseThread = 149 spawn_thread (EscParse, "EscParse", B_DISPLAY_PRIORITY, this); 150 else 151 return B_BAD_THREAD_ID; 152 153 return (resume_thread ( fParseThread)); 154 155 } 156 /////////////////////////////////////////////////////////////////////////// 157 // InitPtyReader ... Initialize and spawn PtyReader thread. 158 // 159 /////////////////////////////////////////////////////////////////////////// 160 thread_id 161 TermParse::InitPtyReader (TermWindow *inWinObj) 162 { 163 164 fWinObj = inWinObj; 165 166 if (fReaderThread < 0) 167 fReaderThread = 168 spawn_thread (PtyReader, "PtyReader", B_NORMAL_PRIORITY, this); 169 else 170 return B_BAD_THREAD_ID; 171 172 fReaderSem = create_sem (0, "pty_reader_sem"); 173 fReaderLocker = create_sem (0, "pty_locker_sem"); 174 175 resume_thread (fReaderThread); 176 177 return (fReaderThread); 178 } 179 180 /* 181 * Constructer and Destructer. 182 */ 183 184 TermParse::TermParse (void) 185 { 186 187 fParseThread = -1; 188 fReaderThread = -1; 189 fLockFlag = 0; 190 fParser_p = 0; 191 fQuitting = 1; 192 193 } 194 195 TermParse::~TermParse (void) 196 { 197 //status_t sts; 198 199 fQuitting = 0; 200 kill_thread(fParseThread); 201 202 kill_thread(fReaderThread); 203 delete_sem (fReaderSem); 204 delete_sem (fReaderLocker); 205 206 } 207 208 ////////////////////////////////////////////////////////////////////////////// 209 // EscParse ... Escape sequence parse and character encoding. 210 // 211 ////////////////////////////////////////////////////////////////////////////// 212 213 extern int utf8_groundtable[]; /* UTF8 Ground table */ 214 extern int cs96_groundtable[]; /* CS96 Ground table */ 215 extern int iso8859_groundtable[]; /* ISO8859 & EUC Ground table */ 216 extern int sjis_groundtable[]; /* Shift-JIS Ground table */ 217 218 extern int esctable[]; /* ESC */ 219 extern int csitable[]; /* ESC [ */ 220 extern int dectable[]; /* ESC [ ? */ 221 extern int scrtable[]; /* ESC # */ 222 extern int igntable[]; /* ignore table */ 223 extern int iestable[]; /* ignore ESC table */ 224 extern int eigtable[]; /* ESC ignore table */ 225 extern int mbcstable[]; /* ESC $ */ 226 227 228 /* MuTerminal coding system (global varriable) */ 229 int gNowCoding = M_UTF8; 230 231 #define DEFAULT -1 232 #define NPARAM 10 // Max parameters 233 234 235 int32 236 TermParse::EscParse(void *data) 237 { 238 int tmp; 239 int top, bot; 240 int cs96; 241 uchar curess = 0; 242 243 TermParse *theObj = (TermParse *)data; 244 245 TermView *viewObj = theObj->fViewObj; 246 CodeConv *convObj = theObj->fConvObj; 247 248 uchar cbuf[4], dstbuf[4]; 249 uchar *ptr; 250 251 int *parsestate, *groundtable; 252 int now_coding = -1; 253 254 uchar c; 255 ushort attr = BACKCOLOR; 256 257 int param[NPARAM]; 258 int nparam = 1; 259 260 int row, col; 261 int width; 262 263 /* default coding system is UTF8 */ 264 groundtable = utf8_groundtable; 265 parsestate = groundtable; 266 267 while (theObj->fQuitting) { 268 c = theObj->GetReaderBuf(); 269 270 if (now_coding != gNowCoding) { 271 /* 272 * Change coding, change parse table. 273 */ 274 switch (gNowCoding) { 275 case M_UTF8: 276 groundtable = utf8_groundtable; 277 break; 278 case M_ISO_8859_1: 279 case M_ISO_8859_2: 280 case M_ISO_8859_3: 281 case M_ISO_8859_4: 282 case M_ISO_8859_5: 283 case M_ISO_8859_6: 284 case M_ISO_8859_7: 285 case M_ISO_8859_8: 286 case M_ISO_8859_9: 287 case M_ISO_8859_10: 288 groundtable = iso8859_groundtable; 289 break; 290 case M_SJIS: 291 groundtable = sjis_groundtable; 292 break; 293 case M_EUC_JP: 294 case M_EUC_KR: 295 case M_ISO_2022_JP: 296 groundtable = iso8859_groundtable; 297 break; 298 } 299 parsestate = groundtable; 300 now_coding = gNowCoding; 301 } 302 303 switch (parsestate[c]) { 304 case CASE_PRINT: 305 cbuf[0] = c; 306 cbuf[1] = '\0'; 307 width = HALF_WIDTH; 308 viewObj->PutChar(cbuf, attr, width); 309 break; 310 311 case CASE_PRINT_GR: 312 /* case iso8859 gr character, or euc */ 313 ptr = cbuf; 314 if (now_coding == M_EUC_JP || now_coding == M_EUC_KR 315 || now_coding == M_ISO_2022_JP) { 316 switch (parsestate[curess]) { 317 case CASE_SS2: /* JIS X 0201 */ 318 *ptr++ = curess; 319 *ptr++ = c; 320 *ptr = 0; 321 width = 1; 322 curess = 0; 323 break; 324 325 case CASE_SS3: /* JIS X 0212 */ 326 *ptr++ = curess; 327 *ptr++ = c; 328 *ptr++ = theObj->GetReaderBuf (); 329 *ptr = 0; 330 width = 2; 331 curess = 0; 332 break; 333 334 default: /* JIS X 0208 */ 335 *ptr++ = c; 336 *ptr++ = theObj->GetReaderBuf (); 337 *ptr = 0; 338 width = 2; 339 break; 340 } 341 } else { 342 /* ISO-8859-1...10 and MacRoman */ 343 *ptr++ = c; 344 *ptr = 0; 345 width = 1; 346 } 347 348 if (now_coding != M_ISO_2022_JP) 349 convObj->ConvertToInternal((char*)cbuf, -1, (char*)dstbuf, now_coding); 350 else 351 convObj->ConvertToInternal((char*)cbuf, -1, (char*)dstbuf, M_EUC_JP); 352 353 viewObj->PutChar(dstbuf, attr, width); 354 break; 355 356 case CASE_PRINT_CS96: 357 cbuf[0] = c | 0x80; 358 cbuf[1] = theObj->GetReaderBuf() | 0x80; 359 cbuf[2] = 0; 360 width = 2; 361 convObj->ConvertToInternal((char*)cbuf, 2, (char*)dstbuf, M_EUC_JP); 362 viewObj->PutChar(dstbuf, attr, width); 363 break; 364 365 case CASE_LF: 366 viewObj->PutLF(); 367 break; 368 369 case CASE_CR: 370 viewObj->PutCR(); 371 break; 372 373 case CASE_SJIS_KANA: 374 cbuf[0] = (uchar)c; 375 cbuf[1] = '\0'; 376 convObj->ConvertToInternal((char*)cbuf, 1, (char*)dstbuf, now_coding); 377 width = 1; 378 viewObj->PutChar(dstbuf, attr, width); 379 break; 380 381 case CASE_SJIS_INSTRING: 382 cbuf[0] = (uchar)c; 383 cbuf[1] = theObj->GetReaderBuf(); 384 cbuf[2] = '\0'; 385 convObj->ConvertToInternal((char*)cbuf, 2, (char*)dstbuf, now_coding); 386 width = 2; 387 viewObj->PutChar(dstbuf, attr, width); 388 break; 389 390 case CASE_UTF8_2BYTE: 391 cbuf[0] = (uchar)c; 392 c = theObj->GetReaderBuf(); 393 if (groundtable[c] != CASE_UTF8_INSTRING) 394 break; 395 cbuf[1] = (uchar)c; 396 cbuf[2] = '\0'; 397 width = convObj->UTF8GetFontWidth((char*)cbuf); 398 viewObj->PutChar(cbuf, attr, width); 399 break; 400 401 case CASE_UTF8_3BYTE: 402 cbuf[0] = c; 403 c = theObj->GetReaderBuf(); 404 if (groundtable[c] != CASE_UTF8_INSTRING) 405 break; 406 cbuf[1] = c; 407 408 c = theObj->GetReaderBuf(); 409 if (groundtable[c] != CASE_UTF8_INSTRING) 410 break; 411 cbuf[2] = c; 412 cbuf[3] = '\0'; 413 width = convObj->UTF8GetFontWidth((char*)cbuf); 414 viewObj->PutChar (cbuf, attr, width); 415 break; 416 417 case CASE_MBCS: 418 /* ESC $ */ 419 parsestate = mbcstable; 420 break; 421 422 case CASE_GSETS: 423 /* ESC $ ? */ 424 parsestate = cs96_groundtable; 425 cs96 = 1; 426 break; 427 428 case CASE_SCS_STATE: 429 cs96 = 0; 430 theObj->GetReaderBuf (); 431 parsestate = groundtable; 432 break; 433 434 case CASE_GROUND_STATE: 435 /* exit ignore mode */ 436 parsestate = groundtable; 437 break; 438 439 case CASE_BELL: 440 beep(); 441 break; 442 443 case CASE_BS: 444 viewObj->MoveCurLeft(1); 445 break; 446 447 case CASE_TAB: 448 tmp = viewObj->GetCurX(); 449 tmp %= 8; 450 viewObj->MoveCurRight(8 - tmp); 451 break; 452 453 case CASE_ESC: 454 /* escape */ 455 parsestate = esctable; 456 break; 457 458 case CASE_IGNORE_STATE: 459 /* Ies: ignore anything else */ 460 parsestate = igntable; 461 break; 462 463 case CASE_IGNORE_ESC: 464 /* Ign: escape */ 465 parsestate = iestable; 466 break; 467 468 case CASE_IGNORE: 469 /* Ignore character */ 470 break; 471 472 case CASE_SI: 473 break; 474 475 case CASE_SO: 476 break; 477 478 case CASE_SCR_STATE: // ESC # 479 /* enter scr state */ 480 parsestate = scrtable; 481 break; 482 483 case CASE_ESC_IGNORE: 484 /* unknown escape sequence */ 485 parsestate = eigtable; 486 break; 487 488 case CASE_ESC_DIGIT: // ESC [ number 489 /* digit in csi or dec mode */ 490 if ((row = param[nparam - 1]) == DEFAULT) 491 row = 0; 492 param[nparam - 1] = 10 * row + (c - '0'); 493 break; 494 495 case CASE_ESC_SEMI: // ESC ; 496 /* semicolon in csi or dec mode */ 497 if (nparam < NPARAM) 498 param[nparam++] = DEFAULT; 499 break; 500 501 case CASE_DEC_STATE: 502 /* enter dec mode */ 503 parsestate = dectable; 504 break; 505 506 case CASE_ICH: // ESC [@ insert charactor 507 /* ICH */ 508 if ((row = param[0]) < 1) 509 row = 1; 510 viewObj->InsertSpace(row); 511 parsestate = groundtable; 512 break; 513 514 case CASE_CUU: // ESC [A cursor up, up arrow key. 515 /* CUU */ 516 if ((row = param[0]) < 1) 517 row = 1; 518 viewObj->MoveCurUp(row); 519 parsestate = groundtable; 520 break; 521 522 case CASE_CUD: // ESC [B cursor down, down arrow key. 523 /* CUD */ 524 if ((row = param[0]) < 1) 525 row = 1; 526 viewObj->MoveCurDown(row); 527 parsestate = groundtable; 528 break; 529 530 case CASE_CUF: // ESC [C cursor forword 531 /* CUF */ 532 if ((row = param[0]) < 1) 533 row = 1; 534 viewObj->MoveCurRight(row); 535 parsestate = groundtable; 536 break; 537 538 case CASE_CUB: // ESC [D cursor backword 539 /* CUB */ 540 if ((row = param[0]) < 1) 541 row = 1; 542 viewObj->MoveCurLeft(row); 543 parsestate = groundtable; 544 break; 545 546 case CASE_CUP: // ESC [...H move cursor 547 /* CUP | HVP */ 548 if ((row = param[0]) < 1) 549 row = 1; 550 if (nparam < 2 || (col = param[1]) < 1) 551 col = 1; 552 553 viewObj->SetCurPos(col - 1, row - 1 ); 554 parsestate = groundtable; 555 break; 556 557 case CASE_ED: // ESC [ ...J clear screen 558 /* ED */ 559 switch (param[0]) { 560 case DEFAULT: 561 case 0: 562 viewObj->EraseBelow(); 563 break; 564 565 case 1: 566 break; 567 568 case 2: 569 viewObj->SetCurPos(0, 0); 570 viewObj->EraseBelow(); 571 break; 572 } 573 parsestate = groundtable; 574 break; 575 576 case CASE_EL: // delete line 577 /* EL */ 578 viewObj->DeleteColumns(); 579 parsestate = groundtable; 580 break; 581 582 case CASE_IL: 583 /* IL */ 584 if ((row = param[0]) < 1) 585 row = 1; 586 viewObj->PutNL(row); 587 parsestate = groundtable; 588 break; 589 590 case CASE_DL: 591 /* DL */ 592 if ((row = param[0]) < 1) 593 row = 1; 594 viewObj->DeleteLine(row); 595 parsestate = groundtable; 596 break; 597 598 case CASE_DCH: 599 /* DCH */ 600 if ((row = param[0]) < 1) 601 row = 1; 602 viewObj->DeleteChar(row); 603 parsestate = groundtable; 604 break; 605 606 case CASE_SET: 607 /* SET */ 608 viewObj->SetInsertMode(MODE_INSERT); 609 parsestate = groundtable; 610 break; 611 612 case CASE_RST: 613 /* RST */ 614 viewObj->SetInsertMode(MODE_OVER); 615 parsestate = groundtable; 616 break; 617 618 case CASE_SGR: 619 /* SGR */ 620 for (row = 0; row < nparam; ++row) { 621 switch (param[row]) { 622 case DEFAULT: 623 case 0: /* Reset attribute */ 624 attr = 0; 625 break; 626 627 case 1: 628 case 5: /* Bold */ 629 attr |= BOLD; 630 break; 631 632 case 4: /* Underline */ 633 attr |= UNDERLINE; 634 break; 635 636 case 7: /* Inverse */ 637 attr |= INVERSE; 638 break; 639 640 case 30: 641 case 31: 642 case 32: 643 case 33: 644 case 34: 645 case 35: 646 case 36: 647 case 37: 648 attr &= ~FORECOLOR; 649 attr |= FORECOLORED(param[row] - 30); 650 attr |= FORESET; 651 break; 652 653 case 39: 654 attr &= ~FORESET; 655 break; 656 657 case 40: 658 case 41: 659 case 42: 660 case 43: 661 case 44: 662 case 45: 663 case 46: 664 case 47: 665 attr &= ~BACKCOLOR; 666 attr |= BACKCOLORED(param[row] - 40); 667 attr |= BACKSET; 668 break; 669 670 case 49: 671 attr &= ~BACKSET; 672 break; 673 } 674 } 675 parsestate = groundtable; 676 break; 677 678 case CASE_CPR: 679 // Q & D hack by Y.Hayakawa (hida@sawada.riec.tohoku.ac.jp) 680 // 21-JUL-99 681 viewObj->DeviceStatusReport(param[0]); 682 parsestate = groundtable; 683 break; 684 685 case CASE_DECSTBM: 686 /* DECSTBM - set scrolling region */ 687 688 if ((top = param[0]) < 1) 689 top = 1; 690 691 if (nparam < 2) 692 bot = -1; 693 else 694 bot = param[1]; 695 696 top--; 697 bot--; 698 699 if (bot > top) 700 viewObj->SetScrollRegion(top, bot); 701 702 parsestate = groundtable; 703 break; 704 705 case CASE_DECREQTPARM: 706 parsestate = groundtable; 707 break; 708 709 case CASE_DECSET: 710 /* DECSET */ 711 // dpmodes(term, bitset); 712 parsestate = groundtable; 713 break; 714 715 case CASE_DECRST: 716 /* DECRST */ 717 // dpmodes(term, bitclr); 718 parsestate = groundtable; 719 break; 720 721 case CASE_DECALN: 722 /* DECALN */ 723 // if(screen->cursor_state) 724 // HideCursor(); 725 // ScrnRefresh(screen, 0, 0, screen->max_row + 1, 726 // screen->max_col + 1, False); 727 parsestate = groundtable; 728 break; 729 730 // case CASE_GSETS: 731 // screen->gsets[scstype] = GSET(c) | cs96; 732 // parsestate = groundtable; 733 // break; 734 735 case CASE_DECSC: 736 /* DECSC */ 737 viewObj->SaveCursor(); 738 parsestate = groundtable; 739 break; 740 741 case CASE_DECRC: 742 /* DECRC */ 743 viewObj->RestoreCursor(); 744 parsestate = groundtable; 745 break; 746 747 case CASE_HTS: 748 /* HTS */ 749 // TabSet(term->tabs, screen->cur_col); 750 parsestate = groundtable; 751 break; 752 753 case CASE_RI: 754 /* RI */ 755 viewObj->ScrollRegion(-1, -1, SCRDOWN, 1); 756 parsestate = groundtable; 757 break; 758 759 case CASE_SS2: 760 /* SS2 */ 761 curess = c; 762 parsestate = groundtable; 763 break; 764 765 case CASE_SS3: 766 /* SS3 */ 767 curess = c; 768 parsestate = groundtable; 769 break; 770 771 case CASE_CSI_STATE: 772 /* enter csi state */ 773 nparam = 1; 774 param[0] = DEFAULT; 775 parsestate = csitable; 776 break; 777 778 case CASE_OSC: 779 /* Operating System Command: ESC ] */ 780 // do_osc(finput); 781 parsestate = groundtable; 782 break; 783 784 case CASE_RIS: // ESC c ... Reset terminal. 785 break; 786 787 case CASE_LS2: 788 /* LS2 */ 789 // screen->curgl = 2; 790 parsestate = groundtable; 791 break; 792 793 case CASE_LS3: 794 /* LS3 */ 795 // screen->curgl = 3; 796 parsestate = groundtable; 797 break; 798 799 case CASE_LS3R: 800 /* LS3R */ 801 // screen->curgr = 3; 802 parsestate = groundtable; 803 break; 804 805 case CASE_LS2R: 806 /* LS2R */ 807 // screen->curgr = 2; 808 parsestate = groundtable; 809 break; 810 811 case CASE_LS1R: 812 /* LS1R */ 813 // screen->curgr = 1; 814 parsestate = groundtable; 815 break; 816 817 default: 818 break; 819 } 820 } 821 theObj->fParseThread = -1; 822 exit_thread(B_OK); 823 return B_OK; 824 } 825 826