xref: /haiku/src/apps/terminal/TermParse.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
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