1 |
/* |
2 |
* HT Editor |
3 |
* vt100.cc - VT100/102 emulator |
4 |
* |
5 |
* Copyright (C) 2003 Stefan Weyergraf |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License version 2 as |
9 |
* published by the Free Software Foundation. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 |
*/ |
20 |
|
21 |
#include <cctype> |
22 |
#include <cstdio> |
23 |
#include <cstring> |
24 |
|
25 |
#include "tools/debug.h" |
26 |
#include "vt100.h" |
27 |
|
28 |
//#define VTERM_LOG_SEQS |
29 |
|
30 |
#ifdef VTERM_LOG_SEQS |
31 |
#define VTERMLOG(a...) DPRINTF(a) |
32 |
#else |
33 |
#define VTERMLOG(a...) |
34 |
#endif |
35 |
|
36 |
static void readCSIParamsMax16(int Pn[], int &n, int &i, const char *buf, int buflen, bool allow_spaces) |
37 |
{ |
38 |
n = 0; |
39 |
char c = buf[i]; |
40 |
char f; |
41 |
do { |
42 |
f = c; |
43 |
int p = 0; |
44 |
while (isdigit(c) || (allow_spaces && (c ==' '))) { |
45 |
if (!(allow_spaces && (c ==' '))) { |
46 |
p *= 10; |
47 |
p += c-'0'; |
48 |
} |
49 |
i++; |
50 |
if (i >= buflen) break; |
51 |
c = buf[i]; |
52 |
} |
53 |
if (!n && (f != ';') && !isdigit(f)) break; |
54 |
Pn[n++] = isdigit(f) ? p : -1; |
55 |
if (i >= buflen) break; |
56 |
if (n == 16) break; |
57 |
if (c != ';') break; |
58 |
i++; |
59 |
c = buf[i]; |
60 |
if (i >= buflen) break; |
61 |
} while (1); |
62 |
} |
63 |
|
64 |
VT100Display::VT100Display(int width, int height, SystemDisplay *aDisplay, vcp initColor) |
65 |
{ |
66 |
mDisplay = aDisplay; |
67 |
x = 0; |
68 |
y = 0; |
69 |
w = width; |
70 |
h = height; |
71 |
mState = PLAIN; |
72 |
mDefaultColor = initColor; |
73 |
mColor = mDefaultColor; |
74 |
mColorLight = false; |
75 |
mG = 0; |
76 |
// this is our default |
77 |
mDECCKM = false; |
78 |
mDECAWM = true; |
79 |
mDECOM = false; |
80 |
mLNM = false; |
81 |
mIM = false; |
82 |
mTermWriteBufLen = 0; |
83 |
mTop = 0; |
84 |
mBottom = h; |
85 |
cursorx = cursory = 1; |
86 |
gotoAbsXY(0, 0); |
87 |
|
88 |
getCursor(mSaved_cursorx, mSaved_cursory); |
89 |
mDisplay->fillAllVT(mColor, ' '); |
90 |
} |
91 |
|
92 |
void VT100Display::getCursor(int &x, int &y) |
93 |
{ |
94 |
x = cursorx; |
95 |
y = cursory; |
96 |
} |
97 |
|
98 |
void VT100Display::doLF() |
99 |
{ |
100 |
VTERMLOG("LF\n"); |
101 |
if (cursory+1 == mBottom) { |
102 |
scrollDown(mTop, mBottom, 1); |
103 |
} else if (cursory < h-1) { |
104 |
cursory++; |
105 |
} |
106 |
} |
107 |
|
108 |
void VT100Display::doCR() |
109 |
{ |
110 |
VTERMLOG("CR\n"); |
111 |
cursorx = 0; |
112 |
} |
113 |
|
114 |
void VT100Display::doBS() |
115 |
{ |
116 |
VTERMLOG("BS\n"); |
117 |
if (cursorx) cursorx--; |
118 |
} |
119 |
|
120 |
void VT100Display::doRI() |
121 |
{ |
122 |
VTERMLOG("RI\n"); |
123 |
if (cursory == mTop) { |
124 |
scrollUp(mTop, mBottom, 1); |
125 |
} else if (cursory > 0) { |
126 |
cursory--; |
127 |
} |
128 |
} |
129 |
|
130 |
void VT100Display::gotoXY(int ncx, int ncy) |
131 |
{ |
132 |
int min_y, max_y; |
133 |
|
134 |
if (ncx < 0) { |
135 |
cursorx = 0; |
136 |
} else if (ncx > w - 1) { |
137 |
cursorx = w - 1; |
138 |
} else { |
139 |
cursorx = ncx; |
140 |
} |
141 |
|
142 |
if (mDECOM) { |
143 |
min_y = mTop; |
144 |
max_y = mBottom; |
145 |
} else { |
146 |
min_y = 0; |
147 |
max_y = h; |
148 |
} |
149 |
|
150 |
if (ncy < min_y) { |
151 |
cursory = min_y; |
152 |
} else if (ncy >= max_y) { |
153 |
cursory = max_y - 1; |
154 |
} else { |
155 |
cursory = ncy; |
156 |
} |
157 |
} |
158 |
|
159 |
void VT100Display::gotoAbsXY(int ncx, int ncy) |
160 |
{ |
161 |
gotoXY(ncx, mDECOM ? mTop+ncy : ncy); |
162 |
} |
163 |
|
164 |
void VT100Display::saveCursor() |
165 |
{ |
166 |
getCursor(mSaved_cursorx, mSaved_cursory); |
167 |
} |
168 |
|
169 |
void VT100Display::restoreCursor() |
170 |
{ |
171 |
gotoXY(mSaved_cursorx, mSaved_cursory); |
172 |
} |
173 |
|
174 |
void VT100Display::scrollDown(int mTop, int mBottom, int count) |
175 |
{ |
176 |
int n = mBottom-mTop-1; |
177 |
while (count--) { |
178 |
memmove(mDisplay->buf+w*mTop, mDisplay->buf+w*(mTop+1), sizeof *mDisplay->buf * w*n); |
179 |
mDisplay->fillVT(0, mBottom-1, w, 1, mColor, ' '); |
180 |
} |
181 |
} |
182 |
|
183 |
void VT100Display::scrollUp(int mTop, int mBottom, int count) |
184 |
{ |
185 |
int n = mBottom-mTop-1; |
186 |
while (count--) { |
187 |
memmove(mDisplay->buf+w*(mTop+1), mDisplay->buf+w*mTop, sizeof *mDisplay->buf * w*n); |
188 |
mDisplay->fillVT(0, mTop, w, 1, mColor, ' '); |
189 |
} |
190 |
} |
191 |
|
192 |
void VT100Display::termifyColor(int &mColor) |
193 |
{ |
194 |
int fg = VCP_FOREGROUND(mColor); |
195 |
int bg = VCP_BACKGROUND(mColor); |
196 |
// light black != dark gray (but black) on VT100s |
197 |
// if (fg == VC_LIGHT(VC_BLACK)) fg = VC_BLACK; |
198 |
// if (bg == VC_LIGHT(VC_BLACK)) bg = VC_BLACK; |
199 |
mColor = VCP(fg, bg); |
200 |
} |
201 |
|
202 |
void VT100Display::setBounds(int width, int height) |
203 |
{ |
204 |
w = width; |
205 |
h = height; |
206 |
if (cursorx > w-1) cursorx = w-1; |
207 |
if (cursory > h-1) cursory = h-1; |
208 |
if (mSaved_cursorx > w-1) mSaved_cursorx = w-1; |
209 |
if (mSaved_cursory > h-1) mSaved_cursory = h-1; |
210 |
mTop = 0; |
211 |
mBottom = h; |
212 |
} |
213 |
|
214 |
void VT100Display::setGraphicRendition(int r) |
215 |
{ |
216 |
vc ctab[8] = { VC_BLACK, VC_RED, VC_GREEN, VC_YELLOW, VC_BLUE, VC_MAGENTA, VC_CYAN, VC_WHITE }; |
217 |
// VTERMLOG("setgr got %d\non entry: mColorf/g=%d/%d\n", r, VCP_FOREGROUND(mColor), VCP_BACKGROUND(mColor)); |
218 |
if ((r >= 30) && (r <= 37)) { |
219 |
// set foreground ... |
220 |
int i = r-30; |
221 |
vc bg = VCP_BACKGROUND(mColor); |
222 |
vc fg = mColorLight ? VC_LIGHT(ctab[i]) : ctab[i]; |
223 |
mColor = VCP(fg, bg); |
224 |
termifyColor(mColor); |
225 |
} else if ((r >= 40) && (r <= 47)) { |
226 |
// set background ... |
227 |
int i = r-40; |
228 |
vc fg = VCP_FOREGROUND(mColor); |
229 |
mColor = VCP(fg, ctab[i]); |
230 |
// mColor = VCP(fg, VC_LIGHT(VC_WHITE)); |
231 |
termifyColor(mColor); |
232 |
} else if (r == 0) { |
233 |
// normal |
234 |
mColor = mDefaultColor; |
235 |
termifyColor(mColor); |
236 |
// FIXME: |
237 |
mColorLight = false; |
238 |
/* } else if (r == 22) { |
239 |
// normal |
240 |
mColor = VCP(VC_WHITE, VC_BLACK);*/ |
241 |
} else if (r == 1) { |
242 |
// bold |
243 |
vc bg = VCP_BACKGROUND(mColor); |
244 |
vc fg = VCP_FOREGROUND(mColor); |
245 |
mColor = VCP(VC_LIGHT(fg), bg); |
246 |
termifyColor(mColor); |
247 |
mColorLight = true; |
248 |
} else if (r == 39) { |
249 |
// set foreground to default |
250 |
vc bg = VCP_BACKGROUND(mColor); |
251 |
vc fg = VCP_FOREGROUND(mDefaultColor); |
252 |
fg = mColorLight ? VC_LIGHT(fg) : fg; |
253 |
mColor = VCP(fg, bg); |
254 |
termifyColor(mColor); |
255 |
} else if (r == 49) { |
256 |
// set background to default |
257 |
vc fg = VCP_FOREGROUND(mColor); |
258 |
mColor = VCP(fg, VCP_BACKGROUND(mDefaultColor)); |
259 |
termifyColor(mColor); |
260 |
} else { |
261 |
VTERMLOG("unsupported gr. rendition %d\n", r); |
262 |
} |
263 |
// VTERMLOG("on exit: mColorf/g=%d/%d\n", VCP_FOREGROUND(mColor), VCP_BACKGROUND(mColor)); |
264 |
} |
265 |
|
266 |
void VT100Display::setMode(int p, bool newValue) |
267 |
{ |
268 |
if (newValue) { |
269 |
// SM - set mode |
270 |
VTERMLOG("SM - set mode"); |
271 |
} else { |
272 |
// RM - reset mode |
273 |
VTERMLOG("RM - reset mode"); |
274 |
} |
275 |
switch (p) { |
276 |
case 4: |
277 |
mIM = newValue; |
278 |
break; |
279 |
case 20: |
280 |
mLNM = newValue; |
281 |
break; |
282 |
default: |
283 |
VTERMLOG("unsupported set/reset mode %d (new value %d)\n", p, newValue); |
284 |
} |
285 |
} |
286 |
|
287 |
void VT100Display::setPrivateMode(int p, bool newValue) |
288 |
{ |
289 |
if (newValue) { |
290 |
// DECSET - set private mode |
291 |
VTERMLOG("DECSET - set private mode"); |
292 |
} else { |
293 |
// DECRST - reset mode |
294 |
VTERMLOG("DECRST - reset private mode"); |
295 |
} |
296 |
switch (p) { |
297 |
case 1: |
298 |
mDECCKM = newValue; |
299 |
break; |
300 |
case 6: |
301 |
mDECOM = newValue; |
302 |
break; |
303 |
case 7: |
304 |
mDECAWM = newValue; |
305 |
break; |
306 |
case 25: |
307 |
// setCursorMode(newValue ? CURSOR_NORMAL : CURSOR_OFF); |
308 |
break; |
309 |
default: |
310 |
VTERMLOG("unsupported private set/reset mode %d (new value %d)\n", p, newValue); |
311 |
} |
312 |
} |
313 |
|
314 |
void VT100Display::setAutoNewLine(bool b) |
315 |
{ |
316 |
mLNM = b; |
317 |
} |
318 |
|
319 |
void VT100Display::termWrite(const void *aBuf, int buflen) |
320 |
{ |
321 |
ASSERT(mTermWriteBufLen+buflen < (int)sizeof mTermWriteBuf); |
322 |
memcpy(mTermWriteBuf+mTermWriteBufLen, aBuf, buflen); |
323 |
buflen += mTermWriteBufLen; |
324 |
const char *buf = mTermWriteBuf; |
325 |
mTermWriteBufLen = 0; |
326 |
int last_seq_start; |
327 |
for (int i=0; i < buflen; i++) { |
328 |
last_seq_start = i; |
329 |
unsigned char c = buf[i]; |
330 |
switch (c) { |
331 |
case 7: |
332 |
VTERMLOG("BELL ignored\n"); |
333 |
continue; |
334 |
case 8: |
335 |
doBS(); |
336 |
continue; |
337 |
case 9: |
338 |
while (cursorx < w - 1) { |
339 |
cursorx++; |
340 |
if ((cursorx < 0) || (cursorx % 8==0)) break; |
341 |
} |
342 |
continue; |
343 |
case 10: |
344 |
case 11: |
345 |
case 12: |
346 |
doLF(); |
347 |
if (!mLNM) continue; |
348 |
case 13: |
349 |
doCR(); |
350 |
continue; |
351 |
case 14: |
352 |
// select G1 |
353 |
VTERMLOG("select G1\n"); |
354 |
mG = 1; |
355 |
continue; |
356 |
case 15: |
357 |
// select G0 |
358 |
VTERMLOG("select G0\n"); |
359 |
mG = 0; |
360 |
continue; |
361 |
case 24: case 26: |
362 |
VTERMLOG("24/26 ignored\n"); |
363 |
mState = PLAIN; |
364 |
continue; |
365 |
case 27: |
366 |
mState = ESC; |
367 |
continue; |
368 |
} |
369 |
switch (mState) { |
370 |
case PLAIN: |
371 |
if ((c >= 32) /* && (c <= 128)*/) { |
372 |
// if (c <32) c = 'X'; |
373 |
// if (mG == 0) { |
374 |
mDisplay->drawChar(cursorx, cursory, mColor, (byte)c); |
375 |
// } else { |
376 |
// mDisplay->drawChar(cursorx, cursory, mColor, gc2mygc((byte)c), CP_GRAPHICAL); |
377 |
// } |
378 |
if (cursorx < w-1) { |
379 |
cursorx++; |
380 |
} else { |
381 |
if (mDECAWM) { |
382 |
doCR(); |
383 |
doLF(); |
384 |
} |
385 |
} |
386 |
VTERMLOG("'%c' cxy=%d,%d colorf/b=%d/%d\n", c, cursorx, cursory, VCP_FOREGROUND(mColor), VCP_BACKGROUND(mColor)); |
387 |
} else { |
388 |
// char buf[128]; |
389 |
// sprintf(buf, "unsupported PLAIN char %d/0x%0x\n", (byte)c, (byte)c); |
390 |
// VTERMLOG(buf); |
391 |
mDisplay->drawChar(cursorx, cursory, mColor, c-0x80); |
392 |
// printChar(cursorx, cursory, mColor, ' '); |
393 |
if (cursorx < w-1) { |
394 |
cursorx++; |
395 |
} else { |
396 |
if (mDECAWM) { |
397 |
doCR(); |
398 |
doLF(); |
399 |
} |
400 |
} |
401 |
} |
402 |
break; |
403 |
case ESC: |
404 |
switch (c) { |
405 |
case '[': |
406 |
mState = CSI; |
407 |
break; |
408 |
case ']': |
409 |
mState = OSC; |
410 |
break; |
411 |
case '7': |
412 |
VTERMLOG("ESC-7: save cursor\n"); |
413 |
saveCursor(); |
414 |
mState = PLAIN; |
415 |
break; |
416 |
case '8': |
417 |
VTERMLOG("ESC-8: restore cursor\n"); |
418 |
restoreCursor(); |
419 |
mState = PLAIN; |
420 |
break; |
421 |
case 'D': { |
422 |
VTERMLOG("ESC-D: line feed\n"); |
423 |
doLF(); |
424 |
mState = PLAIN; |
425 |
break; |
426 |
} |
427 |
case 'E': { |
428 |
VTERMLOG("ESC-E: CR,LF\n"); |
429 |
doCR(); |
430 |
doLF(); |
431 |
mState = PLAIN; |
432 |
break; |
433 |
} |
434 |
case 'M': { |
435 |
VTERMLOG("ESC-M: cursor up\n"); |
436 |
doRI(); |
437 |
mState = PLAIN; |
438 |
break; |
439 |
} |
440 |
case '(': |
441 |
i++; |
442 |
if (i >= buflen) break; |
443 |
c = buf[i]; |
444 |
VTERMLOG("G0 set charset (%c)\n", c); |
445 |
switch (c) { |
446 |
case '0': |
447 |
mColor = VCP(VC_WHITE, VC_BLUE); |
448 |
break; |
449 |
default: |
450 |
mColor = VCP(VC_WHITE, VC_BLACK); |
451 |
} |
452 |
i++; |
453 |
mState = PLAIN; |
454 |
break; |
455 |
case ')': |
456 |
i++; |
457 |
if (i >= buflen) break; |
458 |
c = buf[i]; |
459 |
VTERMLOG("G1 set charset (%c)\n", c); |
460 |
switch (c) { |
461 |
case '0': |
462 |
mColor = VCP(VC_WHITE, VC_BLUE); |
463 |
break; |
464 |
default: |
465 |
mColor = VCP(VC_WHITE, VC_BLACK); |
466 |
} |
467 |
i++; |
468 |
mState = PLAIN; |
469 |
break; |
470 |
case '*': |
471 |
i++; |
472 |
if (i >= buflen) break; |
473 |
c = buf[i]; |
474 |
VTERMLOG("G2 set charset (%c)\n", c); |
475 |
switch (c) { |
476 |
case '0': |
477 |
mColor = VCP(VC_WHITE, VC_BLUE); |
478 |
break; |
479 |
default: |
480 |
mColor = VCP(VC_WHITE, VC_BLACK); |
481 |
} |
482 |
i++; |
483 |
mState = PLAIN; |
484 |
break; |
485 |
case '+': |
486 |
i++; |
487 |
if (i >= buflen) break; |
488 |
c = buf[i]; |
489 |
VTERMLOG("G3 set charset (%c)\n", c); |
490 |
switch (c) { |
491 |
case '0': |
492 |
mColor = VCP(VC_WHITE, VC_BLUE); |
493 |
break; |
494 |
default: |
495 |
mColor = VCP(VC_WHITE, VC_BLACK); |
496 |
} |
497 |
i++; |
498 |
mState = PLAIN; |
499 |
break; |
500 |
case '=': |
501 |
VTERMLOG("set decckm\n"); |
502 |
mDECCKM = true; |
503 |
mState = PLAIN; |
504 |
break; |
505 |
case '>': |
506 |
VTERMLOG("reset decckm\n"); |
507 |
mDECCKM = false; |
508 |
mState = PLAIN; |
509 |
break; |
510 |
default: { |
511 |
VTERMLOG("unsupported ESC-sequence '%c'\n", c); |
512 |
mState = PLAIN; |
513 |
} |
514 |
} |
515 |
break; |
516 |
#define CSI_ARG(idx, defaultval) (((idx<n) && (Pn[idx] != -1)) ? Pn[idx] : defaultval) |
517 |
case CSI_QM: |
518 |
case CSI: { |
519 |
int Pn[16]; |
520 |
int n; |
521 |
// VTERMLOG("CSI-fmt: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", buf[i+0], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7], buf[i+8], buf[i+9], buf[i+10], buf[i+11], buf[i+12], buf[i+13], buf[i+14], buf[i+15]); |
522 |
readCSIParamsMax16(Pn, n, i, buf, buflen, false); |
523 |
if (i >= buflen) break; |
524 |
c = buf[i]; |
525 |
switch (c) { |
526 |
case 'A': { |
527 |
// CUU - cursor up (stop at top) |
528 |
VTERMLOG("CUU - cursor up\n"); |
529 |
int p = CSI_ARG(0, 1); |
530 |
gotoXY(cursorx, cursory-p); |
531 |
mState = PLAIN; |
532 |
break; |
533 |
} |
534 |
case 'B': { |
535 |
// CUD - cursor down (stop at bottom) |
536 |
VTERMLOG("CUD - cursor down\n"); |
537 |
int p = CSI_ARG(0, 1); |
538 |
gotoXY(cursorx, cursory+p); |
539 |
mState = PLAIN; |
540 |
break; |
541 |
} |
542 |
case 'C': { |
543 |
// CUF - cursor forward/right (stop at far right) |
544 |
VTERMLOG("CUF - cursor forward\n"); |
545 |
int p = CSI_ARG(0, 1); |
546 |
gotoXY(cursorx+p, cursory); |
547 |
mState = PLAIN; |
548 |
break; |
549 |
} |
550 |
case 'D': { |
551 |
// CUB - cursor backward/left (stop at far left) |
552 |
VTERMLOG("CUB - cursor backward\n"); |
553 |
int p = CSI_ARG(0, 1); |
554 |
gotoXY(cursorx-p, cursory); |
555 |
mState = PLAIN; |
556 |
break; |
557 |
} |
558 |
case 'E': { |
559 |
// ? - cursor ? |
560 |
VTERMLOG("? - cursor ? (1)\n"); |
561 |
int p = CSI_ARG(0, 1); |
562 |
gotoXY(0, cursory+p); |
563 |
mState = PLAIN; |
564 |
break; |
565 |
} |
566 |
case 'F': { |
567 |
// ? - cursor ? |
568 |
VTERMLOG("? - cursor ? (2)\n"); |
569 |
int p = CSI_ARG(0, 1); |
570 |
gotoXY(0, cursory-p); |
571 |
mState = PLAIN; |
572 |
break; |
573 |
} |
574 |
case '`': |
575 |
case 'G': { |
576 |
// CHA - cursor x position |
577 |
VTERMLOG("CHA - set cursor x\n"); |
578 |
int p = CSI_ARG(0, 1); |
579 |
gotoXY(p-1, cursory); |
580 |
mState = PLAIN; |
581 |
break; |
582 |
} |
583 |
case 'd': { |
584 |
// VPA - cursor y position |
585 |
VTERMLOG("VPA - set cursor y\n"); |
586 |
int p = CSI_ARG(0, 1); |
587 |
gotoAbsXY(cursorx, p-1); |
588 |
mState = PLAIN; |
589 |
break; |
590 |
} |
591 |
case 'f': |
592 |
case 'H': { |
593 |
// CUP - cursor position |
594 |
VTERMLOG("CUP - set cursor\n"); |
595 |
int py = CSI_ARG(0, 1); |
596 |
int px = CSI_ARG(1, 1); |
597 |
gotoAbsXY(px-1, py-1); |
598 |
mState = PLAIN; |
599 |
break; |
600 |
} |
601 |
case 'J': { |
602 |
// ED - erase in screen (cursor does not move) |
603 |
int p = CSI_ARG(0, 0); |
604 |
switch (p) { |
605 |
case 0: |
606 |
// erase from cursor(inclusive) to end of screen |
607 |
VTERMLOG("ED 0 - erase from cursor(inclusive) to end of screen\n"); |
608 |
mDisplay->fillVT(cursorx, cursory, w-cursorx, 1, mColor, ' '); |
609 |
mDisplay->fillVT(0, cursory+1, w, h-cursory-1, mColor, ' '); |
610 |
break; |
611 |
case 1: |
612 |
// erase from beginning of screen to cursor(inclusive) |
613 |
VTERMLOG("ED 1 - erase from beginning of screen to cursor(inclusive)\n"); |
614 |
mDisplay->fillVT(0, 0, w, cursory, mColor, ' '); |
615 |
mDisplay->fillVT(0, cursory, cursorx+1, 1, mColor, ' '); |
616 |
break; |
617 |
case 2: |
618 |
// erase whole screen |
619 |
VTERMLOG("ED 2 - erase whole screen\n"); |
620 |
mDisplay->fillVT(0, 0, w, h, mColor, ' '); |
621 |
break; |
622 |
default: |
623 |
VTERMLOG("ED ? - unsupported !\n"); |
624 |
} |
625 |
mState = PLAIN; |
626 |
break; |
627 |
} |
628 |
case 'K': { |
629 |
// EL - erase in line (cursor does not move) |
630 |
int p = CSI_ARG(0, 0); |
631 |
switch (p) { |
632 |
case 0: |
633 |
// erase from cursor(inclusive) to EOL |
634 |
VTERMLOG("EL 0 - erase in line: from cursor to EOL\n"); |
635 |
mDisplay->fillVT(cursorx, cursory, w-cursorx, 1, mColor, ' '); |
636 |
break; |
637 |
case 1: |
638 |
// erase from BOL to cursor(inclusive) |
639 |
VTERMLOG("EL 1 - erase in line: from BOL to cursor\n"); |
640 |
mDisplay->fillVT(0, cursory, cursorx+1, 1, mColor, ' '); |
641 |
break; |
642 |
case 2: |
643 |
// erase line containing cursor |
644 |
VTERMLOG("EL 2 - erase line containing cursor\n"); |
645 |
mDisplay->fillVT(0, cursory, w, 1, mColor, ' '); |
646 |
break; |
647 |
default: |
648 |
VTERMLOG("EL ? - unsupported !\n"); |
649 |
} |
650 |
mState = PLAIN; |
651 |
break; |
652 |
} |
653 |
case 'L': { |
654 |
// IL - insert n lines (from cursor) |
655 |
VTERMLOG("IL - insert n lines(s)\n"); |
656 |
int p = CSI_ARG(0, 1); |
657 |
if (p > h-cursory) VTERMLOG("DL: sc1 !!!"); |
658 |
if (p > h-cursory) p = h-cursory; |
659 |
if (p < 0) p = 0; |
660 |
scrollUp(cursory, mBottom, p); |
661 |
mState = PLAIN; |
662 |
break; |
663 |
} |
664 |
case 'M': { |
665 |
// DL - delete n lines (from cursor) |
666 |
VTERMLOG("DL - delete n lines(s)\n"); |
667 |
int p = CSI_ARG(0, 1); |
668 |
if (p > h-cursory) VTERMLOG("DL: sc1 !!!"); |
669 |
if (p > h-cursory) p = h-cursory; |
670 |
if (p < 0) p = 0; |
671 |
scrollDown(cursory, mBottom, p); |
672 |
mState = PLAIN; |
673 |
break; |
674 |
} |
675 |
case 'P': { |
676 |
// DCH - delete n chars (from cursor) |
677 |
VTERMLOG("DCH - delete n character(s)\n"); |
678 |
int p = CSI_ARG(0, 1); |
679 |
if (p > w-cursorx) VTERMLOG("DCH: sc1 !!!"); |
680 |
if (p > w-cursorx) p = w-cursorx; |
681 |
if (p < 0) p = 0; |
682 |
BufferedChar *b = mDisplay->buf+w*cursory; |
683 |
memmove(b+cursorx, b+cursorx+p, sizeof (BufferedChar) * (w-cursorx-p)); |
684 |
mDisplay->fillVT(w-p, cursory, p, 1, mColor, ' '); |
685 |
mState = PLAIN; |
686 |
break; |
687 |
} |
688 |
case 'X': { |
689 |
// ECH - erase n chars (from cursor) |
690 |
VTERMLOG("ECH - erase n character(s)\n"); |
691 |
int p = CSI_ARG(0, 1); |
692 |
if (p > w-cursorx) VTERMLOG("ECH: sc1 !!!\n"); |
693 |
if (p > w-cursorx) p = w-cursorx; |
694 |
if (p < 0) p = 0; |
695 |
mDisplay->fillVT(cursorx, cursory, p, 1, mColor, ' '); |
696 |
mState = PLAIN; |
697 |
break; |
698 |
} |
699 |
case '@': { |
700 |
// ICH - insert (blank) character(s) |
701 |
VTERMLOG("ICH - insert (blank) character(s)\n"); |
702 |
int p = CSI_ARG(0, 1); |
703 |
if (p > w-cursorx) VTERMLOG("ICH: sc1 !!!"); |
704 |
if (p > w-cursorx) p = w-cursorx; |
705 |
if (p < 0) p = 0; |
706 |
BufferedChar *b = mDisplay->buf+w*cursory; |
707 |
memmove(b+cursorx+p, b+cursorx, sizeof (BufferedChar) * (w-cursorx-p)); |
708 |
mDisplay->fillVT(cursorx, cursory, p, 1, mColor, ' '); |
709 |
mState = PLAIN; |
710 |
break; |
711 |
} |
712 |
case 'r': { |
713 |
// set scroll region |
714 |
VTERMLOG("DECSTBM - set scroll region\n"); |
715 |
int r1 = CSI_ARG(0, 1); |
716 |
int r2 = CSI_ARG(1, h); |
717 |
if ((r1 > 0) && (r1 < r2) && (r2 <= h)) { |
718 |
mTop = r1-1; |
719 |
mBottom = r2; |
720 |
gotoAbsXY(0, 0); |
721 |
} |
722 |
mState = PLAIN; |
723 |
break; |
724 |
} |
725 |
case 's': { |
726 |
// save cursor |
727 |
VTERMLOG("? - save cursor\n"); |
728 |
saveCursor(); |
729 |
mState = PLAIN; |
730 |
break; |
731 |
} |
732 |
case 'u': { |
733 |
// restore cursor |
734 |
VTERMLOG("? - restore cursor\n"); |
735 |
restoreCursor(); |
736 |
mState = PLAIN; |
737 |
break; |
738 |
} |
739 |
case 'm': { |
740 |
// SGR - select graphic rendition |
741 |
VTERMLOG("SGR - set graphic rendition\n"); |
742 |
for (int k=0; k<n; k++) { |
743 |
setGraphicRendition(CSI_ARG(k, 0)); |
744 |
} |
745 |
if (n == 0) setGraphicRendition(0); |
746 |
mState = PLAIN; |
747 |
break; |
748 |
} |
749 |
case 'h': |
750 |
case 'l': { |
751 |
bool newValue = (c=='h'); |
752 |
int p = CSI_ARG(0, -1); |
753 |
if (mState == CSI) { |
754 |
setMode(p, newValue); |
755 |
} else { |
756 |
setPrivateMode(p, newValue); |
757 |
} |
758 |
mState = PLAIN; |
759 |
break; |
760 |
} |
761 |
case '?': { |
762 |
mState = CSI_QM; |
763 |
break; |
764 |
} |
765 |
default: |
766 |
VTERMLOG("unsupported CSI-sequence '%c' (", c); |
767 |
for (int k=0; k<n; k++) { |
768 |
VTERMLOG("%d", Pn[k]); |
769 |
if (k+1<n) VTERMLOG(", "); |
770 |
} |
771 |
VTERMLOG(")\n"); |
772 |
mState = PLAIN; |
773 |
} |
774 |
VTERMLOG("("); |
775 |
for (int k=0; k<n; k++) { |
776 |
VTERMLOG("%d", Pn[k]); |
777 |
if (k+1<n) VTERMLOG(", "); |
778 |
} |
779 |
VTERMLOG("), cxy=%d,%d\n", cursorx, cursory); |
780 |
break; |
781 |
} |
782 |
#undef CSI_ARG |
783 |
case OSC: { |
784 |
int p = 0; |
785 |
while ((i< buflen) && isdigit(c)) { |
786 |
p *= 10; |
787 |
p += c-'0'; |
788 |
c = buf[++i]; |
789 |
} |
790 |
// skip ';' |
791 |
c = buf[++i]; |
792 |
while ((i<buflen) && (c>=32)) { |
793 |
c = buf[++i]; |
794 |
} |
795 |
if (i >= buflen) break; |
796 |
switch (p) { |
797 |
case 0: { |
798 |
VTERMLOG("OSC: set text params\n"); |
799 |
VTERMLOG("%c%c%c%c%c%c\n", buf[start], buf[start+1], buf[start+2], buf[start+3], buf[start+4], buf[start+5]); |
800 |
mState = PLAIN; |
801 |
break; |
802 |
} |
803 |
default: |
804 |
VTERMLOG("unsupported OSC-sequence no. %d\n", p); |
805 |
mState = PLAIN; |
806 |
} |
807 |
break; |
808 |
} |
809 |
} |
810 |
if (i >= buflen) { |
811 |
memmove(mTermWriteBuf, mTermWriteBuf+last_seq_start, buflen-last_seq_start); |
812 |
mTermWriteBufLen = buflen-last_seq_start; |
813 |
break; |
814 |
} |
815 |
} |
816 |
} |
817 |
|
818 |
static int vcToAnsi(char *buf, vc color, bool fg) |
819 |
{ |
820 |
vc ctab[8] = { VC_BLACK, VC_RED, VC_GREEN, VC_YELLOW, VC_BLUE, VC_MAGENTA, VC_CYAN, VC_WHITE }; |
821 |
int ansi = -1; |
822 |
for (int i=0; i<8; i++) if (ctab[i] == VC_GET_BASECOLOR(color)) { |
823 |
ansi = i; |
824 |
break; |
825 |
} |
826 |
if (ansi != -1) { |
827 |
bool ansibold = VC_GET_LIGHT(color); |
828 |
if (ansibold) { |
829 |
return sprintf(buf, "%d;1", (fg?0:10)+30+ansi); |
830 |
} else { |
831 |
return sprintf(buf, "%d", (fg?0:10)+30+ansi); |
832 |
} |
833 |
} |
834 |
return 0; |
835 |
} |
836 |
|
837 |
void vcpToAnsi(char *buf32, vcp color) |
838 |
{ |
839 |
int i = 0; |
840 |
i += sprintf(buf32+i, "\e["); |
841 |
int fga = vcToAnsi(buf32+i, VCP_FOREGROUND(color), true); |
842 |
i += fga; |
843 |
if (fga) i += sprintf(buf32+i, ";"); |
844 |
int bga = vcToAnsi(buf32+i, VCP_BACKGROUND(color), false); |
845 |
i += bga; |
846 |
if (!bga && !fga) { |
847 |
*buf32 = 0; |
848 |
return; |
849 |
} |
850 |
if (!bga) i--; |
851 |
i += sprintf(buf32+i, "m"); |
852 |
} |
853 |
|