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