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