/* * Copyright (c) 2003-4 Kian Duffy * Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files or portions * thereof (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject * to the following conditions: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright notice * in the binary, as well as this list of conditions and the following * disclaimer in the documentation and/or other materials provided with * the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ #include #include #include #include #include #include #include #include #include "TermParse.h" #include "TermView.h" #include "VTparse.h" #include "TermConst.h" #include "CodeConv.h" extern int pfd; // defined Muterminal.cpp ///////////////////////////////////////////////////////////////////////////// // PtyReader ... Get character from pty device. // ///////////////////////////////////////////////////////////////////////////// int32 TermParse::PtyReader (void *data) { int nread; uint read_p = 0; TermParse *theObj = (TermParse *) data; uchar buf [READ_BUF_SIZE]; while (theObj->fQuitting) { /* * If Pty Buffer nearly full, snooze this thread, and continue. */ if ((read_p - theObj->fParser_p) > READ_BUF_SIZE - 16) { theObj->fLockFlag = READ_BUF_SIZE / 2; acquire_sem (theObj->fReaderLocker); } /* * Read PTY. */ nread = read (pfd, buf, READ_BUF_SIZE - (read_p - theObj->fParser_p)); if (nread <= 0) { be_app->PostMessage(B_QUIT_REQUESTED); exit_thread (B_ERROR); } int left = READ_BUF_SIZE - (read_p % READ_BUF_SIZE); int mod = read_p % READ_BUF_SIZE; /* * Copy read string to PtyBuffer. */ if (nread >= left) { memcpy (theObj->fReadBuf + mod, buf, left); memcpy (theObj->fReadBuf, buf + left, nread - left); } else { memcpy (theObj->fReadBuf + mod, buf, nread); } read_p += nread; /* * Release semaphore. Number of semaphore counter is nread. */ release_sem_etc (theObj->fReaderSem, nread, 0); } theObj->fReaderThread = -1; exit_thread (B_OK); return B_OK; } /////////////////////////////////////////////////////////////////////////// // GetReaderBuf ... Get char pty reader buffer. // /////////////////////////////////////////////////////////////////////////// uchar TermParse::GetReaderBuf (void) { int c; switch (acquire_sem_etc (fReaderSem, 1, B_TIMEOUT, (bigtime_t)10000.0)) { case B_NO_ERROR: break; case B_TIMED_OUT: default: fViewObj->ScrollAtCursor(); fViewObj->UpdateLine(); // Reset cursor blinking time and turn on cursor blinking. fCursorUpdate->SetInterval (1000000); fViewObj->SetCurDraw (CURON); // wait new input from pty. acquire_sem (fReaderSem); break; } c = fReadBuf[fParser_p % READ_BUF_SIZE]; fParser_p++; /* * If PtyReader thread locked, decliment counter and unlock thread. */ if (fLockFlag != 0) { fLockFlag--; if (fLockFlag == 0) { release_sem (fReaderLocker); } } fViewObj->SetCurDraw (CUROFF); return c; } /////////////////////////////////////////////////////////////////////////// // InitTermParse ... Initialize and spawn EscParse thread. // /////////////////////////////////////////////////////////////////////////// status_t TermParse::InitTermParse (TermView *inViewObj, CodeConv *inConvObj) { fViewObj = inViewObj; fConvObj = inConvObj; fCursorUpdate = new BMessageRunner (BMessenger (fViewObj), new BMessage (MSGRUN_CURSOR), 1000000); if (fParseThread < 0) fParseThread = spawn_thread (EscParse, "EscParse", B_DISPLAY_PRIORITY, this); else return B_BAD_THREAD_ID; return (resume_thread ( fParseThread)); } /////////////////////////////////////////////////////////////////////////// // InitPtyReader ... Initialize and spawn PtyReader thread. // /////////////////////////////////////////////////////////////////////////// thread_id TermParse::InitPtyReader (TermWindow *inWinObj) { fWinObj = inWinObj; if (fReaderThread < 0) fReaderThread = spawn_thread (PtyReader, "PtyReader", B_NORMAL_PRIORITY, this); else return B_BAD_THREAD_ID; fReaderSem = create_sem (0, "pty_reader_sem"); fReaderLocker = create_sem (0, "pty_locker_sem"); resume_thread (fReaderThread); return (fReaderThread); } /* * Constructer and Destructer. */ TermParse::TermParse (void) { fParseThread = -1; fReaderThread = -1; fLockFlag = 0; fParser_p = 0; fQuitting = 1; } TermParse::~TermParse (void) { //status_t sts; fQuitting = 0; kill_thread(fParseThread); kill_thread(fReaderThread); delete_sem (fReaderSem); delete_sem (fReaderLocker); } ////////////////////////////////////////////////////////////////////////////// // EscParse ... Escape sequence parse and character encoding. // ////////////////////////////////////////////////////////////////////////////// extern int utf8_groundtable[]; /* UTF8 Ground table */ extern int cs96_groundtable[]; /* CS96 Ground table */ extern int iso8859_groundtable[]; /* ISO8859 & EUC Ground table */ extern int sjis_groundtable[]; /* Shift-JIS Ground table */ extern int esctable[]; /* ESC */ extern int csitable[]; /* ESC [ */ extern int dectable[]; /* ESC [ ? */ extern int scrtable[]; /* ESC # */ extern int igntable[]; /* ignore table */ extern int iestable[]; /* ignore ESC table */ extern int eigtable[]; /* ESC ignore table */ extern int mbcstable[]; /* ESC $ */ /* MuTerminal coding system (global varriable) */ int gNowCoding = M_UTF8; #define DEFAULT -1 #define NPARAM 10 // Max parameters int32 TermParse::EscParse (void *data) { int tmp; int top, bot; int cs96; uchar curess = 0; TermParse *theObj = (TermParse *) data; TermView *viewObj = theObj->fViewObj; CodeConv *convObj = theObj->fConvObj; uchar cbuf[4], dstbuf[4]; uchar *ptr; int *parsestate, *groundtable; int now_coding = -1; uchar c; ushort attr = BACKCOLOR; int param[NPARAM]; int nparam = 1; int row, col; int width; /* default coding system is UTF8 */ groundtable = utf8_groundtable; parsestate = groundtable; while (theObj->fQuitting) { c = theObj->GetReaderBuf (); if (now_coding != gNowCoding) { /* * Change coding, change parse table. */ switch (gNowCoding) { case M_UTF8: groundtable = utf8_groundtable; break; case M_ISO_8859_1: case M_ISO_8859_2: case M_ISO_8859_3: case M_ISO_8859_4: case M_ISO_8859_5: case M_ISO_8859_6: case M_ISO_8859_7: case M_ISO_8859_8: case M_ISO_8859_9: case M_ISO_8859_10: groundtable = iso8859_groundtable; break; case M_SJIS: groundtable = sjis_groundtable; break; case M_EUC_JP: case M_EUC_KR: case M_ISO_2022_JP: groundtable = iso8859_groundtable; break; } parsestate = groundtable; now_coding = gNowCoding; } switch (parsestate[c]) { case CASE_PRINT: cbuf[0] = (uchar) c; cbuf[1] = '\0'; width = HALF_WIDTH; viewObj->PutChar (cbuf, attr, width); break; case CASE_PRINT_GR: /* case iso8859 gr character, or euc */ ptr = cbuf; if (now_coding == M_EUC_JP || now_coding == M_EUC_KR || now_coding == M_ISO_2022_JP) { switch (parsestate[curess]) { case CASE_SS2: /* JIS X 0201 */ *ptr++ = curess; *ptr++ = c; *ptr = 0; width = 1; curess = 0; break; case CASE_SS3: /* JIS X 0212 */ *ptr++ = curess; *ptr++ = c; *ptr++ = theObj->GetReaderBuf (); *ptr = 0; width = 2; curess = 0; break; default: /* JIS X 0208 */ *ptr++ = c; *ptr++ = theObj->GetReaderBuf (); *ptr = 0; width = 2; break; } } else { /* ISO-8859-1...10 and MacRoman */ *ptr++ = c; *ptr = 0; width = 1; } if (now_coding != M_ISO_2022_JP) { convObj->ConvertToInternal (cbuf, dstbuf, now_coding); } else { convObj->ConvertToInternal (cbuf, dstbuf, M_EUC_JP); } viewObj->PutChar (dstbuf, attr, width); break; case CASE_PRINT_CS96: cbuf[0] = c | 0x80; cbuf[1] = theObj->GetReaderBuf() | 0x80; cbuf[2] = 0; width = 2; convObj->ConvertToInternal (cbuf, dstbuf, M_EUC_JP); viewObj->PutChar (dstbuf, attr, width); break; case CASE_LF: viewObj->PutLF (); break; case CASE_CR: viewObj->PutCR (); break; case CASE_SJIS_KANA: cbuf[0] = (uchar) c; cbuf[1] = '\0'; convObj->ConvertToInternal (cbuf, dstbuf, now_coding); width = 1; viewObj->PutChar (dstbuf, attr, width); break; case CASE_SJIS_INSTRING: cbuf[0] = (uchar) c; cbuf[1] = theObj->GetReaderBuf (); cbuf[2] = '\0'; convObj->ConvertToInternal (cbuf, dstbuf, now_coding); width = 2; viewObj->PutChar (dstbuf, attr, width); break; case CASE_UTF8_2BYTE: cbuf[0] = (uchar) c; c =theObj->GetReaderBuf (); if (groundtable[c] != CASE_UTF8_INSTRING) break; cbuf[1] = (uchar) c; cbuf[2] = '\0'; width = convObj->UTF8GetFontWidth (cbuf); viewObj->PutChar (cbuf, attr, width); break; case CASE_UTF8_3BYTE: cbuf[0] = (uchar) c; c =theObj->GetReaderBuf (); if (groundtable[c] != CASE_UTF8_INSTRING) break; cbuf[1] = (uchar) c; c =theObj->GetReaderBuf (); if (groundtable[c] != CASE_UTF8_INSTRING) break; cbuf[2] = (uchar) c; cbuf[3] = '\0'; width = convObj->UTF8GetFontWidth (cbuf); viewObj->PutChar (cbuf, attr, width); break; case CASE_MBCS: /* ESC $ */ parsestate = mbcstable; break; case CASE_GSETS: /* ESC $ ? */ parsestate = cs96_groundtable; cs96 = 1; break; case CASE_SCS_STATE: cs96 = 0; theObj->GetReaderBuf (); parsestate = groundtable; break; case CASE_GROUND_STATE: /* exit ignore mode */ parsestate = groundtable; break; case CASE_BELL: beep(); break; case CASE_BS: viewObj->MoveCurLeft (1); break; case CASE_TAB: tmp = viewObj->GetCurX (); tmp %= 8; viewObj->MoveCurRight (8-tmp); break; case CASE_ESC: /* escape */ parsestate = esctable; break; case CASE_IGNORE_STATE: /* Ies: ignore anything else */ parsestate = igntable; break; case CASE_IGNORE_ESC: /* Ign: escape */ parsestate = iestable; break; case CASE_IGNORE: /* Ignore character */ break; case CASE_SI: break; case CASE_SO: break; case CASE_SCR_STATE: // ESC # /* enter scr state */ parsestate = scrtable; break; case CASE_ESC_IGNORE: /* unknown escape sequence */ parsestate = eigtable; break; case CASE_ESC_DIGIT: // ESC [ number /* digit in csi or dec mode */ if((row = param[nparam - 1]) == DEFAULT) row = 0; param[nparam - 1] = 10 * row + (c - '0'); break; case CASE_ESC_SEMI: // ESC ; /* semicolon in csi or dec mode */ if (nparam < NPARAM) param[nparam++] = DEFAULT; break; case CASE_DEC_STATE: /* enter dec mode */ parsestate = dectable; break; case CASE_ICH: // ESC [@ insert charactor /* ICH */ if((row = param[0]) < 1) row = 1; viewObj->InsertSpace (row); parsestate = groundtable; break; case CASE_CUU: // ESC [A cursor up, up arrow key. /* CUU */ if((row = param[0]) < 1) row = 1; viewObj->MoveCurUp (row); parsestate = groundtable; break; case CASE_CUD: // ESC [B cursor down, down arrow key. /* CUD */ if((row = param[0]) < 1) row = 1; viewObj->MoveCurDown (row); parsestate = groundtable; break; case CASE_CUF: // ESC [C cursor forword /* CUF */ if((row = param[0]) < 1) row = 1; viewObj->MoveCurRight (row); parsestate = groundtable; break; case CASE_CUB: // ESC [D cursor backword /* CUB */ if((row = param[0]) < 1) row = 1; viewObj->MoveCurLeft (row); parsestate = groundtable; break; case CASE_CUP: // ESC [...H move cursor /* CUP | HVP */ if((row = param[0]) < 1) row = 1; if(nparam < 2 || (col = param[1]) < 1) col = 1; viewObj->SetCurPos (col - 1, row - 1 ); parsestate = groundtable; break; case CASE_ED: // ESC [ ...J clear screen /* ED */ switch (param[0]) { case DEFAULT: case 0: viewObj->EraseBelow (); break; case 1: break; case 2: viewObj->SetCurPos (0, 0); viewObj->EraseBelow (); break; } parsestate = groundtable; break; case CASE_EL: // delete line /* EL */ viewObj->DeleteColumns (); parsestate = groundtable; break; case CASE_IL: /* IL */ if((row = param[0]) < 1) row = 1; viewObj->PutNL (row); parsestate = groundtable; break; case CASE_DL: /* DL */ if((row = param[0]) < 1) row = 1; viewObj->DeleteLine (row); parsestate = groundtable; break; case CASE_DCH: /* DCH */ if((row = param[0]) < 1) row = 1; viewObj->DeleteChar(row); parsestate = groundtable; break; case CASE_SET: /* SET */ viewObj->SetInsertMode (MODE_INSERT); parsestate = groundtable; break; case CASE_RST: /* RST */ viewObj->SetInsertMode (MODE_OVER); parsestate = groundtable; break; case CASE_SGR: /* SGR */ for (row=0; rowDeviceStatusReport(param[0]) ; parsestate = groundtable; break; case CASE_DECSTBM: /* DECSTBM - set scrolling region */ if((top = param[0]) < 1) top = 1; if(nparam < 2) { bot = -1; } else { bot = param[1]; } top--; bot --; if (bot > top) { viewObj->SetScrollRegion (top, bot); } parsestate = groundtable; break; case CASE_DECREQTPARM: parsestate = groundtable; break; case CASE_DECSET: /* DECSET */ // dpmodes(term, bitset); parsestate = groundtable; break; case CASE_DECRST: /* DECRST */ // dpmodes(term, bitclr); parsestate = groundtable; break; case CASE_DECALN: /* DECALN */ // if(screen->cursor_state) // HideCursor(); // ScrnRefresh(screen, 0, 0, screen->max_row + 1, // screen->max_col + 1, False); parsestate = groundtable; break; // case CASE_GSETS: // screen->gsets[scstype] = GSET(c) | cs96; // parsestate = groundtable; // break; case CASE_DECSC: /* DECSC */ viewObj->SaveCursor (); parsestate = groundtable; break; case CASE_DECRC: /* DECRC */ viewObj->RestoreCursor (); parsestate = groundtable; break; case CASE_HTS: /* HTS */ // TabSet(term->tabs, screen->cur_col); parsestate = groundtable; break; case CASE_RI: /* RI */ viewObj->ScrollRegion (-1, -1, SCRDOWN, 1); parsestate = groundtable; break; case CASE_SS2: /* SS2 */ curess = c; parsestate = groundtable; break; case CASE_SS3: /* SS3 */ curess = c; parsestate = groundtable; break; case CASE_CSI_STATE: /* enter csi state */ nparam = 1; param[0] = DEFAULT; parsestate = csitable; break; case CASE_OSC: /* Operating System Command: ESC ] */ // do_osc(finput); parsestate = groundtable; break; case CASE_RIS: // ESC c ... Reset terminal. break; case CASE_LS2: /* LS2 */ // screen->curgl = 2; parsestate = groundtable; break; case CASE_LS3: /* LS3 */ // screen->curgl = 3; parsestate = groundtable; break; case CASE_LS3R: /* LS3R */ // screen->curgr = 3; parsestate = groundtable; break; case CASE_LS2R: /* LS2R */ // screen->curgr = 2; parsestate = groundtable; break; case CASE_LS1R: /* LS1R */ // screen->curgr = 1; parsestate = groundtable; break; default: break; } } theObj->fParseThread = -1; exit_thread (B_OK); return B_OK; }