2 * Copyright 2001-2013, 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.
8 * Kian Duffy, myob@users.sourceforge.net
9 * Siarzhuk Zharski, zharik@gmx.li
13 //! Escape sequence parse and character encoding.
16 #include "TermParse.h"
34 #include "TermConst.h"
35 #include "TerminalBuffer.h"
39 extern int gUTF8GroundTable
[]; /* UTF8 Ground table */
40 extern int gISO8859GroundTable
[]; /* ISO8859 & EUC Ground table */
41 extern int gWinCPGroundTable
[]; /* Windows cp1252, cp1251, koi-8r */
42 extern int gSJISGroundTable
[]; /* Shift-JIS Ground table */
44 extern int gEscTable
[]; /* ESC */
45 extern int gCsiTable
[]; /* ESC [ */
46 extern int gDecTable
[]; /* ESC [ ? */
47 extern int gScrTable
[]; /* ESC # */
48 extern int gIgnoreTable
[]; /* ignore table */
49 extern int gIesTable
[]; /* ignore ESC table */
50 extern int gEscIgnoreTable
[]; /* ESC ignore table */
52 extern const char* gLineDrawGraphSet
[]; /* may be used for G0, G1, G2, G3 */
55 #define NPARAM 10 // Max parameters
58 //! Get char from pty reader buffer.
60 TermParse::_NextParseChar()
62 if (fParserBufferOffset
>= fParserBufferSize
) {
63 // parser buffer empty
64 status_t error
= _ReadParserBuffer();
69 #ifdef USE_DEBUG_SNAPSHOTS
70 fBuffer
->CaptureChar(fParserBuffer
[fParserBufferOffset
]);
73 return fParserBuffer
[fParserBufferOffset
++];
77 TermParse::TermParse(int fd
)
87 fParserBufferOffset(0),
91 memset(fReadBuffer
, 0, READ_BUF_SIZE
);
92 memset(fParserBuffer
, 0, ESC_PARSER_BUFFER_SIZE
);
96 TermParse::~TermParse()
103 TermParse::StartThreads(TerminalBuffer
*buffer
)
111 status_t status
= _InitPtyReader();
117 status
= _InitTermParse();
129 TermParse::StopThreads()
145 //! Initialize and spawn EscParse thread.
147 TermParse::_InitTermParse()
149 if (fParseThread
>= 0)
150 return B_ERROR
; // we might want to return B_OK instead ?
152 fParseThread
= spawn_thread(_escparse_thread
, "EscParse",
153 B_DISPLAY_PRIORITY
, this);
155 if (fParseThread
< 0)
158 resume_thread(fParseThread
);
164 //! Initialize and spawn PtyReader thread.
166 TermParse::_InitPtyReader()
168 if (fReaderThread
>= 0)
169 return B_ERROR
; // same as above
171 fReaderSem
= create_sem(0, "pty_reader_sem");
175 fReaderLocker
= create_sem(0, "pty_locker_sem");
176 if (fReaderLocker
< 0) {
177 delete_sem(fReaderSem
);
179 return fReaderLocker
;
182 fReaderThread
= spawn_thread(_ptyreader_thread
, "PtyReader",
183 B_NORMAL_PRIORITY
, this);
184 if (fReaderThread
< 0) {
185 delete_sem(fReaderSem
);
187 delete_sem(fReaderLocker
);
189 return fReaderThread
;
192 resume_thread(fReaderThread
);
199 TermParse::_StopTermParse()
201 if (fParseThread
>= 0) {
203 wait_for_thread(fParseThread
, &dummy
);
210 TermParse::_StopPtyReader()
212 if (fReaderSem
>= 0) {
213 delete_sem(fReaderSem
);
216 if (fReaderLocker
>= 0) {
217 delete_sem(fReaderLocker
);
221 if (fReaderThread
>= 0) {
222 suspend_thread(fReaderThread
);
225 wait_for_thread(fReaderThread
, &status
);
232 //! Get data from pty device.
234 TermParse::PtyReader()
236 int32 bufferSize
= 0;
239 // If Pty Buffer nearly full, snooze this thread, and continue.
240 while (READ_BUF_SIZE
- bufferSize
< MIN_PTY_BUFFER_SPACE
) {
243 status
= acquire_sem(fReaderLocker
);
244 } while (status
== B_INTERRUPTED
);
248 bufferSize
= fReadBufferSize
;
252 uchar buf
[READ_BUF_SIZE
];
253 ssize_t nread
= read(fFd
, buf
, READ_BUF_SIZE
- bufferSize
);
255 fBuffer
->NotifyQuit(errno
);
259 // Copy read string to PtyBuffer.
261 int32 left
= READ_BUF_SIZE
- readPos
;
264 memcpy(fReadBuffer
+ readPos
, buf
, left
);
265 memcpy(fReadBuffer
, buf
+ left
, nread
- left
);
267 memcpy(fReadBuffer
+ readPos
, buf
, nread
);
269 bufferSize
= atomic_add(&fReadBufferSize
, nread
);
271 release_sem(fReaderSem
);
274 readPos
= (readPos
+ nread
) % READ_BUF_SIZE
;
282 TermParse::DumpState(int *groundtable
, int *parsestate
, uchar c
)
284 static const struct {
291 T(gISO8859GroundTable
),
292 T(gWinCPGroundTable
),
304 fprintf(stderr
, "groundtable: ");
305 for (i
= 0; tables
[i
].p
; i
++) {
306 if (tables
[i
].p
== groundtable
)
307 fprintf(stderr
, "%s\t", tables
[i
].name
);
309 fprintf(stderr
, "parsestate: ");
310 for (i
= 0; tables
[i
].p
; i
++) {
311 if (tables
[i
].p
== parsestate
)
312 fprintf(stderr
, "%s\t", tables
[i
].name
);
314 fprintf(stderr
, "char: 0x%02x (%d)\n", c
, c
);
319 TermParse::_GuessGroundTable(int encoding
)
322 case B_ISO1_CONVERSION
:
323 case B_ISO2_CONVERSION
:
324 case B_ISO3_CONVERSION
:
325 case B_ISO4_CONVERSION
:
326 case B_ISO5_CONVERSION
:
327 case B_ISO6_CONVERSION
:
328 case B_ISO7_CONVERSION
:
329 case B_ISO8_CONVERSION
:
330 case B_ISO9_CONVERSION
:
331 case B_ISO10_CONVERSION
:
332 case B_ISO13_CONVERSION
:
333 case B_ISO14_CONVERSION
:
334 case B_ISO15_CONVERSION
:
335 case B_EUC_CONVERSION
:
336 case B_EUC_KR_CONVERSION
:
337 case B_JIS_CONVERSION
:
338 case B_BIG5_CONVERSION
:
339 return gISO8859GroundTable
;
341 case B_KOI8R_CONVERSION
:
342 case B_MS_WINDOWS_1251_CONVERSION
:
343 case B_MS_WINDOWS_CONVERSION
:
344 case B_MAC_ROMAN_CONVERSION
:
345 case B_MS_DOS_866_CONVERSION
:
346 case B_GBK_CONVERSION
:
347 case B_MS_DOS_CONVERSION
:
348 return gWinCPGroundTable
;
350 case B_SJIS_CONVERSION
:
351 return gSJISGroundTable
;
358 return gUTF8GroundTable
;
363 TermParse::EscParse()
368 char cbuf
[4] = { 0 };
369 char dstbuf
[4] = { 0 };
371 int currentEncoding
= -1;
375 for (int i
= 0; i
< NPARAM
; i
++)
381 // default encoding system is UTF8
382 int *groundtable
= gUTF8GroundTable
;
383 int *parsestate
= gUTF8GroundTable
;
385 // handle alternative character sets G0 - G4
386 const char** graphSets
[4] = { NULL
, NULL
, NULL
, NULL
};
390 BAutolock
locker(fBuffer
);
394 uchar c
= _NextParseChar();
396 //DumpState(groundtable, parsestate, c);
398 if (currentEncoding
!= fBuffer
->Encoding()) {
399 // Change coding, change parse table.
400 groundtable
= _GuessGroundTable(fBuffer
->Encoding());
401 parsestate
= groundtable
;
402 currentEncoding
= fBuffer
->Encoding();
405 //debug_printf("TermParse: char: '%c' (%d), parse state: %d\n", c, c, parsestate[c]);
407 int32 dstLen
= sizeof(dstbuf
);
408 int32 dummyState
= 0;
410 switch (parsestate
[c
]) {
413 int curGS
= c
< 128 ? curGL
: curGR
;
414 const char** curGraphSet
= graphSets
[curGS
];
415 if (curGraphSet
!= NULL
) {
416 int offset
= c
- (c
< 128 ? 0x20 : 0xA0);
417 if (offset
>= 0 && offset
< 96
418 && curGraphSet
[offset
] != 0) {
419 fBuffer
->InsertChar(curGraphSet
[offset
]);
423 fBuffer
->InsertChar((char)c
);
428 /* case iso8859 gr character, or euc */
429 switch (currentEncoding
) {
430 case B_EUC_CONVERSION
:
431 case B_EUC_KR_CONVERSION
:
432 case B_JIS_CONVERSION
:
433 case B_BIG5_CONVERSION
:
435 c
= _NextParseChar();
439 case B_GBK_CONVERSION
:
442 // GBK-compatible codepoints are 2-bytes long
443 c
= _NextParseChar();
446 // GB18030 extends GBK with 4-byte codepoints
447 // using 2nd byte from range 0x30...0x39
448 if (srcLen
== 2 && (c
< 0x30 || c
> 0x39))
450 } while (srcLen
< 4);
453 default: // ISO-8859-1...10 and MacRoman
459 int encoding
= currentEncoding
== B_JIS_CONVERSION
460 ? B_EUC_CONVERSION
: currentEncoding
;
462 convert_to_utf8(encoding
, cbuf
, &srcLen
,
463 dstbuf
, &dstLen
, &dummyState
, '?');
465 fBuffer
->InsertChar(UTF8Char(dstbuf
, dstLen
));
480 parsestate
= groundtable
;
485 parsestate
= groundtable
;
490 convert_to_utf8(currentEncoding
, cbuf
, &srcLen
,
491 dstbuf
, &dstLen
, &dummyState
, '?');
492 fBuffer
->InsertChar(UTF8Char(dstbuf
, dstLen
));
495 case CASE_SJIS_INSTRING
:
497 c
= _NextParseChar();
500 convert_to_utf8(currentEncoding
, cbuf
, &srcLen
,
501 dstbuf
, &dstLen
, &dummyState
, '?');
502 fBuffer
->InsertChar(UTF8Char(dstbuf
, dstLen
));
505 case CASE_UTF8_2BYTE
:
507 c
= _NextParseChar();
508 if (groundtable
[c
] != CASE_UTF8_INSTRING
)
512 fBuffer
->InsertChar(UTF8Char(cbuf
, srcLen
));
515 case CASE_UTF8_3BYTE
:
519 c
= _NextParseChar();
520 if (groundtable
[c
] != CASE_UTF8_INSTRING
) {
526 } while (srcLen
!= 3);
529 fBuffer
->InsertChar(UTF8Char(cbuf
, srcLen
));
556 char page
= _NextParseChar();
559 graphSets
[set
] = gLineDrawGraphSet
;
562 graphSets
[set
] = NULL
;
567 parsestate
= groundtable
;
571 case CASE_GROUND_STATE
:
572 /* exit ignore mode */
573 parsestate
= groundtable
;
581 fBuffer
->MoveCursorLeft(1);
585 fBuffer
->InsertTab();
590 parsestate
= gEscTable
;
593 case CASE_IGNORE_STATE
:
594 /* Ies: ignore anything else */
595 parsestate
= gIgnoreTable
;
598 case CASE_IGNORE_ESC
:
600 parsestate
= gIesTable
;
604 /* Ignore character */
608 /* select G1 into GL */
610 parsestate
= groundtable
;
614 /* select G0 into GL */
616 parsestate
= groundtable
;
619 case CASE_SCR_STATE
: // ESC #
620 /* enter scr state */
621 parsestate
= gScrTable
;
624 case CASE_ESC_IGNORE
:
625 /* unknown escape sequence */
626 parsestate
= gEscIgnoreTable
;
629 case CASE_ESC_DIGIT
: // ESC [ number
630 /* digit in csi or dec mode */
631 if ((row
= param
[nparam
- 1]) == DEFAULT
)
633 param
[nparam
- 1] = 10 * row
+ (c
- '0');
636 case CASE_ESC_SEMI
: // ESC ;
637 /* semicolon in csi or dec mode */
639 param
[nparam
++] = DEFAULT
;
642 case CASE_CSI_SP
: // ESC [N q
643 // part of change cursor style DECSCUSR
645 param
[nparam
++] = ' ';
650 parsestate
= gDecTable
;
653 case CASE_ICH
: // ESC [@ insert charactor
655 if ((row
= param
[0]) < 1)
657 fBuffer
->InsertSpace(row
);
658 parsestate
= groundtable
;
661 case CASE_CUU
: // ESC [A cursor up, up arrow key.
663 if ((row
= param
[0]) < 1)
665 fBuffer
->MoveCursorUp(row
);
666 parsestate
= groundtable
;
669 case CASE_CUD
: // ESC [B cursor down, down arrow key.
671 if ((row
= param
[0]) < 1)
673 fBuffer
->MoveCursorDown(row
);
674 parsestate
= groundtable
;
677 case CASE_CUF
: // ESC [C cursor forword
679 if ((row
= param
[0]) < 1)
681 fBuffer
->MoveCursorRight(row
);
682 parsestate
= groundtable
;
685 case CASE_CUB
: // ESC [D cursor backword
687 if ((row
= param
[0]) < 1)
689 fBuffer
->MoveCursorLeft(row
);
690 parsestate
= groundtable
;
693 case CASE_CUP
: // ESC [...H move cursor
695 if ((row
= param
[0]) < 1)
697 if (nparam
< 2 || (column
= param
[1]) < 1)
700 fBuffer
->SetCursor(column
- 1, row
- 1 );
701 parsestate
= groundtable
;
704 case CASE_ED
: // ESC [ ...J clear screen
709 fBuffer
->EraseBelow();
713 fBuffer
->EraseAbove();
720 parsestate
= groundtable
;
723 case CASE_EL
: // ESC [ ...K delete line
728 fBuffer
->DeleteColumns();
732 fBuffer
->EraseCharsFrom(0, fBuffer
->Cursor().x
+ 1);
736 fBuffer
->DeleteColumnsFrom(0);
739 parsestate
= groundtable
;
744 if ((row
= param
[0]) < 1)
746 fBuffer
->InsertLines(row
);
747 parsestate
= groundtable
;
752 if ((row
= param
[0]) < 1)
754 fBuffer
->DeleteLines(row
);
755 parsestate
= groundtable
;
760 if ((row
= param
[0]) < 1)
762 fBuffer
->DeleteChars(row
);
763 parsestate
= groundtable
;
769 fBuffer
->SetInsertMode(MODE_INSERT
);
770 parsestate
= groundtable
;
776 fBuffer
->SetInsertMode(MODE_OVER
);
777 parsestate
= groundtable
;
783 uint32 attributes
= fBuffer
->GetAttributes();
784 for (row
= 0; row
< nparam
; ++row
) {
785 switch (param
[row
]) {
787 case 0: /* Reset attribute */
796 case 4: /* Underline */
797 attributes
|= UNDERLINE
;
800 case 7: /* Inverse */
801 attributes
|= INVERSE
;
804 case 22: /* Not Bold */
808 case 24: /* Not Underline */
809 attributes
&= ~UNDERLINE
;
812 case 27: /* Not Inverse */
813 attributes
&= ~INVERSE
;
833 attributes
&= ~FORECOLOR
;
834 attributes
|= FORECOLORED(param
[row
] - 30);
835 attributes
|= FORESET
;
841 if (nparam
== 3 && param
[1] == 5)
843 else if (nparam
== 5 && param
[1] == 2)
844 color
= fBuffer
->GuessPaletteColor(
845 param
[2], param
[3], param
[4]);
848 attributes
&= ~FORECOLOR
;
849 attributes
|= FORECOLORED(color
);
850 attributes
|= FORESET
;
853 row
= nparam
; // force exit of the parsing
858 attributes
&= ~FORESET
;
878 attributes
&= ~BACKCOLOR
;
879 attributes
|= BACKCOLORED(param
[row
] - 40);
880 attributes
|= BACKSET
;
886 if (nparam
== 3 && param
[1] == 5)
888 else if (nparam
== 5 && param
[1] == 2)
889 color
= fBuffer
->GuessPaletteColor(
890 param
[2], param
[3], param
[4]);
893 attributes
&= ~BACKCOLOR
;
894 attributes
|= BACKCOLORED(color
);
895 attributes
|= BACKSET
;
898 row
= nparam
; // force exit of the parsing
903 attributes
&= ~BACKSET
;
907 fBuffer
->SetAttributes(attributes
);
908 parsestate
= groundtable
;
913 // Q & D hack by Y.Hayakawa (hida@sawada.riec.tohoku.ac.jp)
915 _DeviceStatusReport(param
[0]);
916 parsestate
= groundtable
;
920 // DA - report device attributes
922 // claim to be a VT102
923 write(fFd
, "\033[?6c", 5);
925 parsestate
= groundtable
;
929 /* DECSTBM - set scrolling region */
931 if ((top
= param
[0]) < 1)
935 bottom
= fBuffer
->Height();
943 fBuffer
->SetScrollRegion(top
, bottom
);
945 parsestate
= groundtable
;
948 case CASE_DECSCUSR_ETC
:
949 // DECSCUSR - set cursor style VT520
950 if (nparam
== 2 && param
[1] == ' ') {
951 bool blinking
= (param
[0] & 0x01) != 0;
958 style
= BLOCK_CURSOR
;
962 style
= UNDERLINE_CURSOR
;
966 style
= IBEAM_CURSOR
;
971 fBuffer
->SetCursorStyle(style
, blinking
);
973 parsestate
= groundtable
;
976 case CASE_DECREQTPARM
:
977 // DEXREQTPARM - request terminal parameters
978 _DecReqTermParms(param
[0]);
979 parsestate
= groundtable
;
984 for (int i
= 0; i
< nparam
; i
++)
985 _DecPrivateModeSet(param
[i
]);
986 parsestate
= groundtable
;
991 for (int i
= 0; i
< nparam
; i
++)
992 _DecPrivateModeReset(param
[i
]);
993 parsestate
= groundtable
;
998 fBuffer
->FillScreen(UTF8Char('E'), 0);
999 parsestate
= groundtable
;
1003 // screen->gsets[scstype] = GSET(c) | cs96;
1004 // parsestate = groundtable;
1009 fBuffer
->SaveCursor();
1010 parsestate
= groundtable
;
1015 fBuffer
->RestoreCursor();
1016 parsestate
= groundtable
;
1021 fBuffer
->SetTabStop(fBuffer
->Cursor().x
);
1022 parsestate
= groundtable
;
1028 fBuffer
->ClearTabStop(fBuffer
->Cursor().x
);
1029 else if (param
[0] == 3)
1030 fBuffer
->ClearAllTabStops();
1031 parsestate
= groundtable
;
1036 fBuffer
->InsertRI();
1037 parsestate
= groundtable
;
1042 parsestate
= groundtable
;
1047 parsestate
= groundtable
;
1050 case CASE_CSI_STATE
:
1051 /* enter csi state */
1054 parsestate
= gCsiTable
;
1059 /* Operating System Command: ESC ] */
1061 // fill the buffer until BEL, ST or something else.
1062 bool isParsed
= false;
1063 int32 skipCount
= 0; // take care about UTF-8 characters
1064 for (uint i
= 0; !isParsed
&& i
< sizeof(params
); i
++) {
1065 params
[i
] = _NextParseChar();
1067 if (skipCount
> 0) {
1072 skipCount
= UTF8Char::ByteCount(params
[i
]) - 1;
1076 switch (params
[i
]) {
1085 // 7-bit ST is "ESC \"
1087 // hm... Was \x1b replaced by 0 during parsing?
1088 if (i
> 0 && params
[i
- 1] == 0) {
1093 if (!isprint(params
[i
] & 0x7f))
1100 // watchdog for the 'end of buffer' case
1101 params
[sizeof(params
) - 1] = '\0';
1104 _ProcessOperatingSystemControls(params
);
1106 parsestate
= groundtable
;
1110 case CASE_RIS
: // ESC c ... Reset terminal.
1114 /* select G2 into GL */
1116 parsestate
= groundtable
;
1120 /* select G3 into GL */
1122 parsestate
= groundtable
;
1126 /* select G3 into GR */
1128 parsestate
= groundtable
;
1132 /* select G2 into GR */
1134 parsestate
= groundtable
;
1138 /* select G1 into GR */
1140 parsestate
= groundtable
;
1143 case CASE_VPA
: // ESC [...d move cursor absolute vertical
1145 if ((row
= param
[0]) < 1)
1148 // note beterm wants it 1-based unlike usual terminals
1149 fBuffer
->SetCursorY(row
- 1);
1150 parsestate
= groundtable
;
1153 case CASE_HPA
: // ESC [...G move cursor absolute horizontal
1155 if ((column
= param
[0]) < 1)
1158 // note beterm wants it 1-based unlike usual terminals
1159 fBuffer
->SetCursorX(column
- 1);
1160 parsestate
= groundtable
;
1163 case CASE_SU
: // scroll screen up
1164 if ((row
= param
[0]) < 1)
1166 fBuffer
->ScrollBy(row
);
1167 parsestate
= groundtable
;
1170 case CASE_SD
: // scroll screen down
1171 if ((row
= param
[0]) < 1)
1173 fBuffer
->ScrollBy(-row
);
1174 parsestate
= groundtable
;
1178 case CASE_ECH
: // erase characters
1179 if ((column
= param
[0]) < 1)
1181 fBuffer
->EraseChars(column
);
1182 parsestate
= groundtable
;
1185 case CASE_CBT
: // cursor back tab
1186 if ((column
= param
[0]) < 1)
1188 fBuffer
->InsertCursorBackTab(column
);
1189 parsestate
= groundtable
;
1192 case CASE_CFT
: // cursor forward tab
1193 if ((column
= param
[0]) < 1)
1195 for (int32 i
= 0; i
< column
; ++i
)
1196 fBuffer
->InsertTab();
1197 parsestate
= groundtable
;
1200 case CASE_CNL
: // cursor next line
1201 if ((row
= param
[0]) < 1)
1203 fBuffer
->SetCursorX(0);
1204 fBuffer
->MoveCursorDown(row
);
1205 parsestate
= groundtable
;
1208 case CASE_CPL
: // cursor previous line
1209 if ((row
= param
[0]) < 1)
1211 fBuffer
->SetCursorX(0);
1212 fBuffer
->MoveCursorUp(row
);
1213 parsestate
= groundtable
;
1228 TermParse::_ptyreader_thread(void *data
)
1230 return reinterpret_cast<TermParse
*>(data
)->PtyReader();
1235 TermParse::_escparse_thread(void *data
)
1237 return reinterpret_cast<TermParse
*>(data
)->EscParse();
1242 TermParse::_ReadParserBuffer()
1244 // We have to unlock the terminal buffer while waiting for data from the
1245 // PTY. We don't have to unlock when we don't need to wait, but we do it
1246 // anyway, so that TermView won't be starved when trying to synchronize.
1249 // wait for new input from pty
1250 if (atomic_get(&fReadBufferSize
) == 0) {
1251 status_t status
= B_OK
;
1252 while (atomic_get(&fReadBufferSize
) == 0 && status
== B_OK
) {
1254 status
= acquire_sem(fReaderSem
);
1255 } while (status
== B_INTERRUPTED
);
1257 // eat any sems that were released unconditionally
1259 if (get_sem_count(fReaderSem
, &semCount
) == B_OK
&& semCount
> 0)
1260 acquire_sem_etc(fReaderSem
, semCount
, B_RELATIVE_TIMEOUT
, 0);
1263 if (status
< B_OK
) {
1269 int32 toRead
= atomic_get(&fReadBufferSize
);
1270 if (toRead
> ESC_PARSER_BUFFER_SIZE
)
1271 toRead
= ESC_PARSER_BUFFER_SIZE
;
1273 for (int32 i
= 0; i
< toRead
; i
++) {
1274 // TODO: This could be optimized using memcpy instead and
1275 // calculating space left as in the PtyReader().
1276 fParserBuffer
[i
] = fReadBuffer
[fBufferPosition
];
1277 fBufferPosition
= (fBufferPosition
+ 1) % READ_BUF_SIZE
;
1280 int32 bufferSize
= atomic_add(&fReadBufferSize
, -toRead
);
1282 // If the pty reader thread waits and we have made enough space in the
1283 // buffer now, let it run again.
1284 if (bufferSize
> READ_BUF_SIZE
- MIN_PTY_BUFFER_SPACE
1285 && bufferSize
- toRead
<= READ_BUF_SIZE
- MIN_PTY_BUFFER_SPACE
) {
1286 release_sem(fReaderLocker
);
1289 fParserBufferSize
= toRead
;
1290 fParserBufferOffset
= 0;
1298 TermParse::_DeviceStatusReport(int n
)
1306 // Device status report requested
1307 // reply with "no malfunction detected"
1308 const char* toWrite
= "\033[0n";
1309 write(fFd
, toWrite
, strlen(toWrite
));
1313 // Cursor position report requested
1314 len
= sprintf(sbuf
, "\033[%" B_PRId32
";%" B_PRId32
"R",
1315 fBuffer
->Cursor().y
+ 1,
1316 fBuffer
->Cursor().x
+ 1);
1317 write(fFd
, sbuf
, len
);
1326 TermParse::_DecReqTermParms(int value
)
1328 // Terminal parameters report:
1331 // 8 bits per character (1);
1332 // transmit speed 38400bps (128);
1333 // receive speed 38400bps (128);
1334 // bit rate multiplier 16 (1);
1336 char parms
[] = "\033[?;1;1;128;128;1;0x";
1340 else if (value
== 1)
1345 write(fFd
, parms
, strlen(parms
));
1350 TermParse::_DecPrivateModeSet(int value
)
1354 // Application Cursor Keys (whatever that means).
1355 // Not supported yet.
1358 // Reverse Video (inverses colors for the complete screen
1359 // -- when followed by normal video, that's shortly flashes the
1361 // Not supported yet.
1365 fBuffer
->SetOriginMode(true);
1368 // Set Mouse X and Y on button press.
1369 fBuffer
->ReportX10MouseEvent(true);
1372 // Start Blinking Cursor.
1373 fBuffer
->SetCursorBlinking(true);
1377 fBuffer
->SetCursorHidden(false);
1380 // Use Alternate Screen Buffer.
1381 fBuffer
->UseAlternateScreenBuffer(false);
1384 // Send Mouse X & Y on button press and release.
1385 fBuffer
->ReportNormalMouseEvent(true);
1388 // Send Mouse X and Y on button press and release, and on motion
1389 // when the mouse enter a new cell
1390 fBuffer
->ReportButtonMouseEvent(true);
1393 // Use All Motion Mouse Tracking
1394 fBuffer
->ReportAnyMouseEvent(true);
1397 // TODO: Interprete "meta" key, sets eighth bit.
1398 // Not supported yet.
1401 // TODO: Send ESC when Meta modifies a key
1402 // Not supported yet.
1405 // TODO: Send ESC when Alt modifies a key
1406 // Not supported yet.
1409 // Save cursor as in DECSC and use Alternate Screen Buffer, clearing
1411 fBuffer
->SaveCursor();
1412 fBuffer
->UseAlternateScreenBuffer(true);
1419 TermParse::_DecPrivateModeReset(int value
)
1423 // Normal Cursor Keys (whatever that means).
1424 // Not supported yet.
1428 // Not supported yet.
1431 // Jump (Fast) Scroll.
1432 // Not supported yet.
1435 // Normal Video (Leaves Reverse Video, cf. there).
1436 // Not supported yet.
1439 // Reset Origin Mode.
1440 fBuffer
->SetOriginMode(false);
1443 // Disable Mouse X and Y on button press.
1444 fBuffer
->ReportX10MouseEvent(false);
1447 // Stop Blinking Cursor.
1448 fBuffer
->SetCursorBlinking(false);
1452 fBuffer
->SetCursorHidden(true);
1455 // Use Normal Screen Buffer.
1456 fBuffer
->UseNormalScreenBuffer();
1459 // Don't send Mouse X & Y on button press and release.
1460 fBuffer
->ReportNormalMouseEvent(false);
1463 // Don't send Mouse X and Y on button press and release, and on motion
1464 // when the mouse enter a new cell
1465 fBuffer
->ReportButtonMouseEvent(false);
1468 // Disable All Motion Mouse Tracking.
1469 fBuffer
->ReportAnyMouseEvent(false);
1472 // Don't interprete "meta" key.
1473 // Not supported yet.
1476 // TODO: Don't send ESC when Meta modifies a key
1477 // Not supported yet.
1480 // TODO: Don't send ESC when Alt modifies a key
1481 // Not supported yet.
1484 // Use Normal Screen Buffer and restore cursor as in DECRC.
1485 fBuffer
->UseNormalScreenBuffer();
1486 fBuffer
->RestoreCursor();
1493 TermParse::_ProcessOperatingSystemControls(uchar
* params
)
1496 for (uchar c
= *params
; c
!= ';' && c
!= '\0'; c
= *(++params
)) {
1501 // eat the separator
1505 static uint8 indexes
[kTermColorCount
];
1506 static rgb_color colors
[kTermColorCount
];
1509 case 0: // icon name and window title
1510 case 2: // window title
1511 fBuffer
->SetTitle((const char*)params
);
1513 case 4: // set colors (0 - 255)
1514 case 104: // reset colors (0 - 255)
1516 bool reset
= (mode
/ 100) == 1;
1518 // colors can be in "idx1:name1;...;idxN:nameN;" sequence too!
1520 char* p
= strtok((char*)params
, ";");
1521 while (p
!= NULL
&& count
< kTermColorCount
) {
1522 indexes
[count
] = atoi(p
);
1525 p
= strtok(NULL
, ";");
1529 if (gXColorsTable
.LookUpColor(p
, &colors
[count
]) == B_OK
)
1534 p
= strtok(NULL
, ";");
1539 fBuffer
->SetColors(indexes
, colors
, count
);
1541 fBuffer
->ResetColors(indexes
, count
);
1545 // set dynamic colors (10 - 19)
1546 case 10: // text foreground
1547 case 11: // text background
1549 int32 offset
= mode
- 10;
1551 char* p
= strtok((char*)params
, ";");
1553 if (gXColorsTable
.LookUpColor(p
, &colors
[count
]) != B_OK
) {
1554 // dyna-colors are pos-sensitive - no chance to continue
1558 indexes
[count
] = 10 + offset
+ count
;
1560 p
= strtok(NULL
, ";");
1562 } while (p
!= NULL
&& (offset
+ count
) < 10);
1565 fBuffer
->SetColors(indexes
, colors
, count
, true);
1569 // reset dynamic colors (10 - 19)
1570 case 110: // text foreground
1571 case 111: // text background
1574 fBuffer
->ResetColors(indexes
, 1, true);
1578 // printf("%d -> %s\n", mode, params);