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