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