alot of renaming...
[k8sterm.git] / src / ttyputc.c
blob21f080bde89d9f3b73198ed39803c2593da39714
1 ////////////////////////////////////////////////////////////////////////////////
2 static void k8t_dbgCSIDump (K8Term *term) {
3 fprintf(stderr, "^[");
4 for (int f = 0; f < term->escseq.len; ++f) {
5 uint32_t c = (term->escseq.buf[f]&0xff);
6 //
7 if (c != 32 && isprint(c)) fputc(c, stderr);
8 else if (c == '\n') fprintf(stderr, "(\\n)");
9 else if (c == '\r') fprintf(stderr, "(\\r)");
10 else if (c == 0x1b) fprintf(stderr, "(\\e)");
11 else fprintf(stderr, "(%u)", c);
13 fputc('\n', stderr);
17 ////////////////////////////////////////////////////////////////////////////////
18 static void k8t_tmResetAttrs (K8Term *term) {
19 term->c.attr.attr &= ~(K8T_ATTR_REVERSE|K8T_ATTR_UNDERLINE|K8T_ATTR_BOLD);
20 term->c.attr.attr |= K8T_ATTR_DEFFG|K8T_ATTR_DEFBG;
21 term->c.attr.fg = term->deffg;
22 term->c.attr.bg = term->defbg;
26 static void k8t_tmSetAttr (K8Term *term, int *attr, int l) {
27 for (int f = 0; f < l; ++f) {
28 switch (attr[f]) {
29 case 0:
30 k8t_tmResetAttrs(term);
31 break;
32 case 1:
33 term->c.attr.attr |= K8T_ATTR_BOLD;
34 break;
35 case 4:
36 term->c.attr.attr |= K8T_ATTR_UNDERLINE;
37 break;
38 case 7:
39 term->c.attr.attr |= K8T_ATTR_REVERSE;
40 break;
41 case 22:
42 term->c.attr.attr &= ~K8T_ATTR_BOLD;
43 break;
44 case 24:
45 term->c.attr.attr &= ~K8T_ATTR_UNDERLINE;
46 break;
47 case 27:
48 term->c.attr.attr &= ~K8T_ATTR_REVERSE;
49 break;
50 case 38:
51 if (f+2 < l && attr[f+1] == 5) {
52 f += 2;
53 if (K8T_BETWEEN(attr[f], 0, 255)) {
54 term->c.attr.fg = attr[f];
55 term->c.attr.attr &= ~K8T_ATTR_DEFFG;
56 } else {
57 fprintf(stderr, "erresc: bad fgcolor %d\n", attr[f]);
59 } else {
60 //fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[f]);
61 term->c.attr.fg = term->deffg;
62 term->c.attr.attr |= K8T_ATTR_DEFFG;
64 break;
65 case 39:
66 term->c.attr.fg = term->deffg;
67 term->c.attr.attr |= K8T_ATTR_DEFFG;
68 break;
69 case 48:
70 if (f+2 < l && attr[f+1] == 5) {
71 f += 2;
72 if (K8T_BETWEEN(attr[f], 0, 255)) {
73 term->c.attr.bg = attr[f];
74 term->c.attr.attr &= ~K8T_ATTR_DEFBG;
75 } else {
76 fprintf(stderr, "erresc: bad bgcolor %d\n", attr[f]);
78 } else {
79 fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[f]);
81 break;
82 case 49:
83 term->c.attr.bg = term->defbg;
84 term->c.attr.attr |= K8T_ATTR_DEFBG;
85 break;
86 default:
87 if (K8T_BETWEEN(attr[f], 30, 37)) { term->c.attr.fg = attr[f]-30; term->c.attr.attr &= ~K8T_ATTR_DEFFG; }
88 else if (K8T_BETWEEN(attr[f], 40, 47)) { term->c.attr.bg = attr[f]-40; term->c.attr.attr &= ~K8T_ATTR_DEFBG; }
89 else if (K8T_BETWEEN(attr[f], 90, 97)) { term->c.attr.fg = attr[f]-90+8; term->c.attr.attr &= ~K8T_ATTR_DEFFG; }
90 else if (K8T_BETWEEN(attr[f], 100, 107)) { term->c.attr.bg = attr[f]-100+8; term->c.attr.attr &= ~K8T_ATTR_DEFBG; }
91 else { fprintf(stderr, "erresc: gfx attr %d unknown\n", attr[f]); k8t_dbgCSIDump(term); }
92 break;
98 // return:
99 // 0: no wrapping
100 // 1: wrapped
101 // -1: no-wrap mode and tries to wrap
102 static int k8t_tmDoWrap (K8Term *term) {
103 if (term->c.state&K8T_CURSOR_WRAPNEXT) {
104 if (K8T_ISSET(term, K8T_MODE_WRAP)) {
105 // always go to first col
106 k8t_tmNewLine(term, 2); // this will reset K8T_CURSOR_WRAPNEXT
107 return 1;
108 } else {
109 k8t_tmCharWrap(term, term->c.y, 0);
110 return -1;
113 return 0;
117 ////////////////////////////////////////////////////////////////////////////////
118 // esc processing
119 static void k8t_tmCSIHandle (K8Term *term) {
120 if (term->dumpescapes) {
121 fprintf(stderr, "CSI: ");
122 k8t_dbgCSIDump(term);
125 switch (term->escseq.mode) {
126 case '@': /* ICH -- Insert <n> blank char */
127 K8T_DEFAULT(term->escseq.arg[0], 1);
128 k8t_tmInsertBlank(term, term->escseq.arg[0]);
129 break;
130 case 'A': /* CUU -- Cursor <n> Up */
131 case 'e':
132 K8T_DEFAULT(term->escseq.arg[0], 1);
133 k8t_tmMoveTo(term, term->c.x, term->c.y-term->escseq.arg[0]);
134 break;
135 case 'B': /* CUD -- Cursor <n> Down */
136 K8T_DEFAULT(term->escseq.arg[0], 1);
137 k8t_tmMoveTo(term, term->c.x, term->c.y+term->escseq.arg[0]);
138 break;
139 case 'C': /* CUF -- Cursor <n> Forward */
140 case 'a':
141 K8T_DEFAULT(term->escseq.arg[0], 1);
142 k8t_tmMoveTo(term, term->c.x+term->escseq.arg[0], term->c.y);
143 break;
144 case 'D': /* CUB -- Cursor <n> Backward */
145 K8T_DEFAULT(term->escseq.arg[0], 1);
146 k8t_tmMoveTo(term, term->c.x-term->escseq.arg[0], term->c.y);
147 break;
148 case 'E': /* CNL -- Cursor <n> Down and first col */
149 K8T_DEFAULT(term->escseq.arg[0], 1);
150 k8t_tmMoveTo(term, 0, term->c.y+term->escseq.arg[0]);
151 break;
152 case 'F': /* CPL -- Cursor <n> Up and first col */
153 K8T_DEFAULT(term->escseq.arg[0], 1);
154 k8t_tmMoveTo(term, 0, term->c.y-term->escseq.arg[0]);
155 break;
156 case 'G': /* CHA -- Move to <col> */
157 case '`': /* XXX: HPA -- same? */
158 K8T_DEFAULT(term->escseq.arg[0], 1);
159 k8t_tmMoveTo(term, term->escseq.arg[0]-1, term->c.y);
160 break;
161 case 'H': /* CUP -- Move to <row> <col> */
162 case 'f': /* XXX: HVP -- same? */
163 K8T_DEFAULT(term->escseq.arg[0], 1);
164 K8T_DEFAULT(term->escseq.arg[1], 1);
165 k8t_tmMoveTo(term, term->escseq.arg[1]-1, term->escseq.arg[0]-1);
166 break;
167 /* XXX: (CSI n I) CHT -- Cursor Forward Tabulation <n> tab stops */
168 case 'J': /* ED -- Clear screen */
169 term->sel.bx = -1;
170 switch (term->escseq.arg[0]) {
171 case 0: /* below */
172 k8t_tmClearRegion(term, term->c.x, term->c.y, term->col-1, term->c.y);
173 if (term->c.y < term->row-1) k8t_tmClearRegion(term, 0, term->c.y+1, term->col-1, term->row-1);
174 break;
175 case 1: /* above */
176 if (term->c.y > 1) k8t_tmClearRegion(term, 0, 0, term->col-1, term->c.y-1);
177 k8t_tmClearRegion(term, 0, term->c.y, term->c.x, term->c.y);
178 break;
179 case 2: /* all */
180 k8t_tmClearRegion(term, 0, 0, term->col-1, term->row-1);
181 break;
182 default:
183 goto unknown;
185 break;
186 case 'K': /* EL -- Clear line */
187 switch (term->escseq.arg[0]) {
188 case 0: /* right */
189 k8t_tmClearRegion(term, term->c.x, term->c.y, term->col-1, term->c.y);
190 break;
191 case 1: /* left */
192 k8t_tmClearRegion(term, 0, term->c.y, term->c.x, term->c.y);
193 break;
194 case 2: /* all */
195 k8t_tmClearRegion(term, 0, term->c.y, term->col-1, term->c.y);
196 break;
198 break;
199 case 'S': /* SU -- Scroll <n> line up */
200 K8T_DEFAULT(term->escseq.arg[0], 1);
201 k8t_tmScrollUp(term, term->top, term->escseq.arg[0], 0);
202 break;
203 case 'T': /* SD -- Scroll <n> line down */
204 K8T_DEFAULT(term->escseq.arg[0], 1);
205 k8t_tmScrollDown(term, term->top, term->escseq.arg[0]);
206 break;
207 case 'L': /* IL -- Insert <n> blank lines */
208 K8T_DEFAULT(term->escseq.arg[0], 1);
209 k8t_tmInsertBlankLine(term, term->escseq.arg[0]);
210 break;
211 case 'l': /* RM -- Reset Mode */
212 if (term->escseq.priv) {
213 switch (term->escseq.arg[0]) {
214 case 1: // 1001 for xterm compatibility
215 DUMP_KEYPAD_SWITCH("1", "OFF");
216 term->mode &= ~K8T_MODE_APPKEYPAD;
217 if (term->dumpeskeys) fprintf(stderr, "*KPMODE: off (1l)\n");
218 break;
219 case 5: /* DECSCNM -- Remove reverse video */
220 if (K8T_ISSET(term, K8T_MODE_REVERSE)) {
221 term->mode &= ~K8T_MODE_REVERSE;
222 k8t_tmFullDirty(term);
224 break;
225 case 7: /* autowrap off */
226 if (K8T_ISSET(term, K8T_MODE_WRAP)) {
227 k8t_tmDoWrap(term);
228 term->mode &= ~K8T_MODE_WRAP;
230 break;
231 case 12: /* att610 -- Stop blinking cursor (IGNORED) */
232 break;
233 case 20: /* non-standard code? */
234 term->mode &= ~K8T_MODE_CRLF;
235 break;
236 case 25: /* hide cursor */
237 if ((term->c.state&K8T_CURSOR_HIDE) == 0) {
238 term->c.state |= K8T_CURSOR_HIDE;
239 k8t_tmWantRedraw(term, 0);
241 break;
242 case 1000: /* disable X11 xterm mouse reporting */
243 term->mode &= ~K8T_MODE_MOUSEBTN;
244 break;
245 case 1002:
246 term->mode &= ~K8T_MODE_MOUSEMOTION;
247 break;
248 case 1004:
249 term->mode &= ~K8T_MODE_FOCUSEVT;
250 break;
251 case 1005: /* utf-8 mouse encoding */
252 case 1006: /* sgr mouse encoding */
253 case 1015: /* urxvt mouse encoding */
254 term->mousemode = 1000;
255 break;
256 case 1049: /* = 1047 and 1048 */
257 case 47:
258 case 1047:
259 if (K8T_ISSET(term, K8T_MODE_ALTSCREEN)) {
260 k8t_tmClearRegion(term, 0, 0, term->col-1, term->row-1);
261 k8t_tmSwapScreen(term);
263 if (term->escseq.arg[0] != 1049) break;
264 case 1048:
265 k8t_tmCursor(term, K8T_CURSOR_LOAD);
266 break;
267 case 2004: /* reset bracketed paste mode */
268 term->mode &= ~K8T_MODE_BRACPASTE;
269 break;
270 default:
271 goto unknown;
273 } else {
274 switch (term->escseq.arg[0]) {
275 //2: Keyboard Action Mode (AM)
276 //12: Send/receive (SRM)
277 //20: Normal Linefeed (LNM)
278 case 3:
279 term->mode &= ~K8T_MODE_DISPCTRL;
280 break;
281 case 4:
282 term->mode &= ~K8T_MODE_INSERT;
283 break;
284 default:
285 goto unknown;
288 break;
289 case 'M': /* DL -- Delete <n> lines */
290 K8T_DEFAULT(term->escseq.arg[0], 1);
291 k8t_tmDeleteLine(term, term->escseq.arg[0]);
292 break;
293 case 'X': /* ECH -- Erase <n> char */
294 K8T_DEFAULT(term->escseq.arg[0], 1);
295 k8t_tmClearRegion(term, term->c.x, term->c.y, term->c.x + term->escseq.arg[0], term->c.y);
296 break;
297 case 'P': /* DCH -- Delete <n> char */
298 K8T_DEFAULT(term->escseq.arg[0], 1);
299 k8t_tmDeleteChar(term, term->escseq.arg[0]);
300 break;
301 /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */
302 case 'd': /* VPA -- Move to <row> */
303 K8T_DEFAULT(term->escseq.arg[0], 1);
304 k8t_tmMoveTo(term, term->c.x, term->escseq.arg[0]-1);
305 break;
306 case 'h': /* SM -- Set terminal mode */
307 if (term->escseq.priv) {
308 switch (term->escseq.arg[0]) {
309 case 1:
310 DUMP_KEYPAD_SWITCH("1", "ON");
311 term->mode |= K8T_MODE_APPKEYPAD;
312 if (term->dumpeskeys) fprintf(stderr, "*KPMODE: on (1h)\n");
313 break;
314 case 5: /* DECSCNM -- Reverve video */
315 if (!K8T_ISSET(term, K8T_MODE_REVERSE)) {
316 term->mode |= K8T_MODE_REVERSE;
317 k8t_tmFullDirty(term);
319 break;
320 case 7:
321 if (!K8T_ISSET(term, K8T_MODE_WRAP)) {
322 if (term->c.state&K8T_CURSOR_WRAPNEXT) k8t_tmMoveTo(term, term->c.x, term->c.y); // reset 'wrap-next' flag
323 term->mode |= K8T_MODE_WRAP;
325 break;
326 case 20:
327 term->mode |= K8T_MODE_CRLF;
328 break;
329 case 12: /* att610 -- Start blinking cursor (IGNORED) */
330 /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
331 if (term->escseq.narg > 1 && term->escseq.arg[1] != 25) break;
332 case 25:
333 if ((term->c.state&K8T_CURSOR_HIDE) != 0) {
334 term->c.state &= ~K8T_CURSOR_HIDE;
335 k8t_tmWantRedraw(term, 0);
337 break;
338 case 1000: /* 1000,1002: enable xterm mouse report */
339 term->mode |= K8T_MODE_MOUSEBTN;
340 break;
341 case 1002:
342 term->mode |= K8T_MODE_MOUSEMOTION;
343 break;
344 case 1004:
345 term->mode |= K8T_MODE_FOCUSEVT;
346 break;
347 case 1005: /* utf-8 mouse encoding */
348 case 1006: /* sgr mouse encoding */
349 case 1015: /* urxvt mouse encoding */
350 term->mousemode = term->escseq.arg[0];
351 break;
352 case 1049: /* = 1047 and 1048 */
353 case 47:
354 case 1047:
355 if (K8T_ISSET(term, K8T_MODE_ALTSCREEN)) k8t_tmClearRegion(term, 0, 0, term->col-1, term->row-1); else k8t_tmSwapScreen(term);
356 if (term->escseq.arg[0] != 1049) break;
357 case 1048:
358 k8t_tmCursor(term, K8T_CURSOR_SAVE);
359 break;
360 case 2004: /* set bracketed paste mode */
361 term->mode |= K8T_MODE_BRACPASTE;
362 break;
363 default: goto unknown;
365 } else {
366 switch (term->escseq.arg[0]) {
367 case 3:
368 term->mode |= K8T_MODE_DISPCTRL;
369 break;
370 case 4:
371 term->mode |= K8T_MODE_INSERT;
372 break;
373 default:
374 goto unknown;
377 break;
378 case 'm': /* SGR -- Terminal attribute (color) */
379 k8t_tmSetAttr(term, term->escseq.arg, term->escseq.narg);
380 break;
381 case 'n':
382 if (!term->escseq.priv) {
383 switch (term->escseq.arg[0]) {
384 case 5: /* Device status report (DSR) */
385 k8t_ttyWriteStr(term, "\x1b[0n");
386 break;
387 case 6: { /* cursor position report */
388 char buf[32];
390 sprintf(buf, "\x1b[%d;%dR", term->c.x+1, term->c.y+1);
391 k8t_ttyWriteStr(term, buf);
392 } break;
395 break;
396 case 'r': /* DECSTBM -- Set Scrolling Region */
397 if (term->escseq.priv && term->escseq.arg[0] == 1001) {
398 // xterm compatibility
399 DUMP_KEYPAD_SWITCH("1001", "OFF");
400 term->mode &= ~K8T_MODE_APPKEYPAD;
401 if (term->dumpeskeys) fprintf(stderr, "*KPMODE: off (1001r)\n");
402 } else if (term->escseq.priv) {
403 goto unknown;
404 } else {
405 K8T_DEFAULT(term->escseq.arg[0], 1);
406 K8T_DEFAULT(term->escseq.arg[1], term->row);
407 k8t_tmSetScrollRegion(term, term->escseq.arg[0]-1, term->escseq.arg[1]-1);
408 k8t_tmMoveTo(term, 0, 0);
410 break;
411 case 's': /* DECSC -- Save cursor position (ANSI.SYS) */
412 if (term->escseq.priv && term->escseq.arg[0] == 1001) {
413 // xterm compatibility
414 DUMP_KEYPAD_SWITCH("1001", "ON");
415 term->mode |= K8T_MODE_APPKEYPAD;
416 if (term->dumpeskeys) fprintf(stderr, "*KPMODE: on (1001s)\n");
417 } else {
418 k8t_tmCursor(term, K8T_CURSOR_SAVE);
420 break;
421 case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
422 k8t_tmCursor(term, K8T_CURSOR_LOAD);
423 break;
424 default:
425 unknown:
426 fprintf(stderr, "erresc: unknown csi ");
427 k8t_dbgCSIDump(term);
428 break;
433 static void k8t_tmCSIReset (K8Term *term) {
434 memset(&term->escseq, 0, sizeof(term->escseq));
438 static void k8t_tmCSIParse (K8Term *term) {
439 const char *p = term->escseq.buf;
441 term->escseq.narg = 0;
442 for (int f = 0; f < K8T_ESC_ARG_SIZ; ++f) term->escseq.arg[f] = 0;
444 if (*p == '?') { term->escseq.priv = 1; ++p; }
445 while (p < term->escseq.buf+term->escseq.len) {
446 int n = term->escseq.arg[term->escseq.narg];
448 for (; *p && isdigit(*p); ++p) n = n*10+(p[0]-'0');
449 term->escseq.arg[term->escseq.narg] = n;
451 if (*p == ';' && term->escseq.narg+1 < K8T_ESC_ARG_SIZ) {
452 ++term->escseq.narg;
453 ++p;
454 } else {
455 term->escseq.mode = *p;
456 ++term->escseq.narg;
457 break;
463 ////////////////////////////////////////////////////////////////////////////////
464 static void k8t_tmPutTab (K8Term *term) {
465 int space = opt_tabsize-term->c.x%opt_tabsize;
467 if (space > 0) k8t_tmMoveTo(term, term->c.x+space, term->c.y);
471 ////////////////////////////////////////////////////////////////////////////////
472 // put char to output buffer or process command
474 // return 1 if this was control character
475 // return -1 if this should break esape sequence
476 static int k8t_tmPutCtrl (K8Term *term, char ascii) {
477 int res = 1;
479 if (term->esc&K8T_ESC_TITLE) return 0;
481 switch (ascii) {
482 case '\t': if (k8t_tmDoWrap(term) >= 0) k8t_tmPutTab(term); break;
483 case '\b': k8t_tmDoWrap(term); k8t_tmMoveTo(term, term->c.x-1, term->c.y); break;
484 case '\r': k8t_tmDoWrap(term); k8t_tmMoveTo(term, 0, term->c.y); break;
485 case '\f': case '\n': case '\v':
486 k8t_tmDoWrap(term);
487 k8t_tmNewLine(term, (K8T_ISSET(term, K8T_MODE_CRLF) ? 1 : 0)); /* go to first col if the mode is set */
488 break;
489 case '\a':
490 if (!(xw.state&K8T_WIN_FOCUSED) && (term->belltype&K8T_BELL_URGENT)) xseturgency(1);
491 if (term->belltype&K8T_BELL_AUDIO) XBell(xw.dpy, 100);
492 break;
493 case 14: term->charset = K8T_MODE_GFX1; break;
494 case 15: term->charset = K8T_MODE_GFX0; break;
495 case 0x18: case 0x1a: res = -1; break; // do nothing, interrupt current escape sequence
496 case 127: break; // ignore it
497 case '\033': k8t_tmCSIReset(term); term->esc = K8T_ESC_START; break;
498 //case 0x9b: k8t_tmCSIReset(term); term->esc = K8T_ESC_START|K8T_ESC_CSI; break;
499 default: res = 0; break;
502 return res;
506 static void k8t_tmPutC (K8Term *term, const char *c) {
507 char ascii = *c;
508 int ctl = k8t_tmPutCtrl(term, ascii);
510 if (ctl > 0) return; // control char; should not break escape sequence
511 if (ctl < 0) {
512 // control char; should break escape sequence
513 term->esc = 0;
514 return;
516 //dlogf("k8t_tmPutC: [%c]\n", c[0]);
517 if (term->esc&K8T_ESC_START) {
518 if (term->esc&K8T_ESC_CSI) {
519 term->escseq.buf[term->escseq.len++] = ascii;
520 if (K8T_BETWEEN(ascii, 0x40, 0x7E) || term->escseq.len >= K8T_ESC_BUF_SIZ) {
521 term->esc = 0;
522 k8t_tmCSIParse(term);
523 k8t_tmCSIHandle(term);
525 } else if (term->esc&K8T_ESC_OSC) {
526 /* TODO: handle other OSC */
527 if (ascii == ';') {
528 term->title[0] = 0;
529 term->titlelen = 0;
530 term->esc = K8T_ESC_START|K8T_ESC_TITLE;
531 //updateTabBar = 1;
533 } else if (term->esc&K8T_ESC_TITLE) {
534 int len = k8t_UTF8Size(c);
536 if (ascii == '\a' || term->titlelen+len >= K8T_ESC_TITLE_SIZ) {
537 term->esc = 0;
538 term->title[term->titlelen] = '\0';
539 if (curterm == term) fixWindowTitle(term);
540 updateTabBar = 1;
541 } else if (len > 0) {
542 memcpy(term->title+term->titlelen, c, len);
543 term->titlelen += len;
544 term->title[term->titlelen] = '\0';
546 } else if (term->esc&K8T_ESC_ALTCHARSET) {
547 term->esc = 0;
548 switch (ascii) {
549 case '0': /* Line drawing crap */
550 term->mode |= K8T_MODE_GFX0;
551 break;
552 case 'B': /* Back to regular text */
553 term->mode &= ~K8T_MODE_GFX0;
554 break;
555 default:
556 fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii);
557 term->mode &= ~K8T_MODE_GFX0;
558 break;
560 } else if (term->esc&K8T_ESC_ALTG1) {
561 term->esc = 0;
562 switch (ascii) {
563 case '0': /* Line drawing crap */
564 term->mode |= K8T_MODE_GFX1;
565 break;
566 case 'B': /* Back to regular text */
567 term->mode &= ~K8T_MODE_GFX1;
568 break;
569 default:
570 fprintf(stderr, "esc unhandled charset: ESC ) %c\n", ascii);
571 term->mode &= ~K8T_MODE_GFX1;
572 break;
574 } else if (term->esc&K8T_ESC_HASH) {
575 term->esc = 0;
576 switch (ascii) {
577 case '8': /* DECALN -- DEC screen alignment test -- fill screen with E's */
578 //tfillscreenwithE();
579 break;
581 } else if (term->esc&K8T_ESC_PERCENT) {
582 term->esc = 0;
583 switch (ascii) {
584 case 'G': case '8':
585 term->needConv = 0;
586 break;
587 default:
588 term->needConv = (needConversion ? 1 : 0);
589 break;
591 } else {
592 switch (ascii) {
593 case '[': term->esc |= K8T_ESC_CSI; break;
594 case ']': term->esc |= K8T_ESC_OSC; break;
595 case '(': term->esc |= K8T_ESC_ALTCHARSET; break;
596 case ')': term->esc |= K8T_ESC_ALTG1; break;
597 case '#': term->esc |= K8T_ESC_HASH; break;
598 case '%': term->esc |= K8T_ESC_PERCENT; break;
599 default: /* other escapes */
600 term->esc = 0;
601 if (term->dumpescapes) {
602 fprintf(stderr, "ESC: ESC 0x%02X ('%c'; %u)\n", (uint8_t)ascii, (isprint(ascii) ? ascii : '.'), (uint8_t)ascii);
604 switch (ascii) {
605 case 'D': /* IND -- Linefeed */
606 k8t_tmDoWrap(term);
607 if (term->c.y == term->bot) k8t_tmScrollUp(term, term->top, 1, 1); else k8t_tmMoveTo(term, term->c.x, term->c.y+1);
608 break;
609 case 'E': /* NEL -- Next line */
610 k8t_tmDoWrap(term);
611 k8t_tmNewLine(term, 1); /* always go to first col */
612 break;
613 case 'M': /* RI -- Reverse linefeed */
614 if (term->c.state&K8T_CURSOR_WRAPNEXT) {
615 k8t_tmCharWrap(term, term->c.y, 0);
616 term->c.state &= ~K8T_CURSOR_WRAPNEXT;
617 if (K8T_ISSET(term, K8T_MODE_WRAP)) {
618 // we should move to the next line, so just stay where we are
619 k8t_tmMoveTo(term, term->c.x, term->c.y);
620 break;
623 if (term->c.y == term->top) k8t_tmScrollDown(term, term->top, 1); else k8t_tmMoveTo(term, term->c.x, term->c.y-1);
624 break;
625 case 'c': /* RIS -- Reset to inital state */
626 k8t_tmReset(term);
627 break;
628 case '=': /* DECPAM -- Application keypad */
629 DUMP_KEYPAD_SWITCH("=", "ON");
630 if (!term->ignoredecpad) {
631 term->mode |= K8T_MODE_APPKEYPAD;
632 if (term->dumpeskeys) fprintf(stderr, "*KPMODE: on (^[=)\n");
634 break;
635 case '>': /* DECPNM -- Normal keypad */
636 DUMP_KEYPAD_SWITCH(">", "OFF");
637 if (!term->ignoredecpad) {
638 term->mode &= ~K8T_MODE_APPKEYPAD;
639 if (term->dumpeskeys) fprintf(stderr, "*KPMODE: off (^[>)\n");
641 break;
642 case '7': /* DECSC -- Save Cursor */
643 /* Save current state (cursor coordinates, attributes, character sets pointed at by G0, G1) */
644 //TODO?
645 k8t_tmCursor(term, K8T_CURSOR_SAVE);
646 break;
647 case '8': /* DECRC -- Restore Cursor */
648 //TODO?
649 k8t_tmCursor(term, K8T_CURSOR_LOAD);
650 break;
651 case 'F': /* Cursor to lower left corner of screen */
652 k8t_tmMoveTo(term, 0, term->row-1);
653 break;
654 case 'Z': /* DEC private identification */
655 k8t_ttyWriteStr(term, "\x1b[?1;2c");
656 break;
657 default:
658 fprintf(stderr, "erresc: unknown sequence ESC 0x%02X ('%c')\n", (uint8_t)ascii, isprint(ascii)?ascii:'.');
659 break;
663 } else {
664 //if (term->sel.bx != -1 && K8T_BETWEEN(term->c.y, term->sel.by, term->sel.ey)) term->sel.bx = -1;
665 do {
666 if (term->needConv && K8T_ISGFX(term->c.attr.attr)) {
667 uint32_t cc;
669 k8t_UTF8Decode(&cc, c);
670 if (cc < 32 || cc >= 127) break; //FIXME: nothing at all?
671 } else {
672 if ((unsigned char)ascii < 32 || ascii == 127) break; // seems that this chars are empty too
675 if (k8t_tmDoWrap(term) < 0) break; // wrapping, but wrap is off, don't want more chars
676 k8t_tmSetChar(term, c);
677 if (term->c.x+1 < term->col) k8t_tmMoveTo(term, term->c.x+1, term->c.y); else term->c.state |= K8T_CURSOR_WRAPNEXT;
678 } while (0);