summaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorCarsten Haitzler <raster@rasterman.com>2012-07-13 08:46:33 +0000
committerCarsten Haitzler <raster@rasterman.com>2012-07-13 08:46:33 +0000
commit197e0bbf46d74b622f43315f0daa9b0f6105a93d (patch)
tree4ce8a1831db77a7e7c3fcc6d1f45cef56e0ceaea /src/bin
parent92d58dc53244f751ef9a0bf0b40600973c230bfa (diff)
splut up termpty a lot. still escape handling is the largest bit -
1200 lines or so, but not a lot that canbe done about that as its the smallest really logical unit there. SVN revision: 73798
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/Makefile.am4
-rw-r--r--src/bin/termpty.c1612
-rw-r--r--src/bin/termpty.h2
-rw-r--r--src/bin/termptyesc.c1224
-rw-r--r--src/bin/termptyesc.h2
-rw-r--r--src/bin/termptyext.c61
-rw-r--r--src/bin/termptyext.h2
-rw-r--r--src/bin/termptygfx.c53
-rw-r--r--src/bin/termptygfx.h2
-rw-r--r--src/bin/termptyops.c354
-rw-r--r--src/bin/termptyops.h21
11 files changed, 1733 insertions, 1604 deletions
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
index dea6235..4f2f0f8 100644
--- a/src/bin/Makefile.am
+++ b/src/bin/Makefile.am
@@ -27,6 +27,10 @@ options_wallpaper.c options_wallpaper.h \
27termio.c termio.h \ 27termio.c termio.h \
28termpty.c termpty.h \ 28termpty.c termpty.h \
29termptydbl.c termptydbl.h \ 29termptydbl.c termptydbl.h \
30termptyesc.c termptyesc.h \
31termptyops.c termptyops.h \
32termptygfx.c termptygfx.h \
33termptyext.c termptyext.h \
30utf8.c utf8.h \ 34utf8.c utf8.h \
31win.c win.h \ 35win.c win.h \
32utils.c utils.h 36utils.c utils.h
diff --git a/src/bin/termpty.c b/src/bin/termpty.c
index 51ec2c9..d6ec000 100644
--- a/src/bin/termpty.c
+++ b/src/bin/termpty.c
@@ -1,8 +1,8 @@
1#include "private.h" 1#include "private.h"
2
3#include <Elementary.h> 2#include <Elementary.h>
4#include "termpty.h" 3#include "termpty.h"
5#include "termptydbl.h" 4#include "termptyesc.h"
5#include "termptyops.h"
6#include <sys/types.h> 6#include <sys/types.h>
7#include <sys/stat.h> 7#include <sys/stat.h>
8#include <stdlib.h> 8#include <stdlib.h>
@@ -12,7 +12,7 @@
12#include <errno.h> 12#include <errno.h>
13 13
14/* specific log domain to help debug only terminal code parser */ 14/* specific log domain to help debug only terminal code parser */
15static int _termpty_log_dom = -1; 15int _termpty_log_dom = -1;
16 16
17#undef CRITICAL 17#undef CRITICAL
18#undef ERR 18#undef ERR
@@ -45,1602 +45,6 @@ termpty_shutdown(void)
45} 45}
46 46
47static void 47static void
48_text_clear(Termpty *ty, Termcell *cells, int count, int val, Eina_Bool inherit_att)
49{
50 int i;
51 Termatt clear;
52
53 memset(&clear, 0, sizeof(clear));
54 if (inherit_att)
55 {
56 for (i = 0; i < count; i++)
57 {
58 cells[i].codepoint = val;
59 cells[i].att = ty->state.att;
60 }
61 }
62 else
63 {
64 for (i = 0; i < count; i++)
65 {
66 cells[i].codepoint = val;
67 cells[i].att = clear;
68 }
69 }
70}
71
72static void
73_text_copy(Termpty *ty __UNUSED__, Termcell *cells, Termcell *dest, int count)
74{
75 memcpy(dest, cells, sizeof(*(cells)) * count);
76}
77
78static void
79_text_save_top(Termpty *ty)
80{
81 Termsave *ts;
82
83 if (ty->backmax <= 0) return;
84 ts = malloc(sizeof(Termsave) + ((ty->w - 1) * sizeof(Termcell)));
85 ts->w = ty->w;
86 _text_copy(ty, ty->screen, ts->cell, ty->w);
87 if (!ty->back) ty->back = calloc(1, sizeof(Termsave *) * ty->backmax);
88 if (ty->back[ty->backpos]) free(ty->back[ty->backpos]);
89 ty->back[ty->backpos] = ts;
90 ty->backpos++;
91 if (ty->backpos >= ty->backmax) ty->backpos = 0;
92 ty->backscroll_num++;
93 if (ty->backscroll_num >= ty->backmax) ty->backscroll_num = ty->backmax - 1;
94}
95
96static void
97_text_scroll(Termpty *ty)
98{
99 Termcell *cells = NULL, *cells2;
100 int y, start_y = 0, end_y = ty->h - 1;
101
102 if (ty->state.scroll_y2 != 0)
103 {
104 start_y = ty->state.scroll_y1;
105 end_y = ty->state.scroll_y2 - 1;
106 }
107 else
108 {
109 if (!ty->altbuf)
110 {
111 _text_save_top(ty);
112 if (ty->cb.scroll.func) ty->cb.scroll.func(ty->cb.scroll.data);
113 }
114 else
115 if (ty->cb.cancel_sel.func)
116 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
117 }
118 DBG("... scroll!!!!! [%i->%i]", start_y, end_y);
119 cells2 = &(ty->screen[end_y * ty->w]);
120 for (y = start_y; y < end_y; y++)
121 {
122 cells = &(ty->screen[y * ty->w]);
123 cells2 = &(ty->screen[(y + 1) * ty->w]);
124 _text_copy(ty, cells2, cells, ty->w);
125 }
126 _text_clear(ty, cells2, ty->w, ' ', EINA_TRUE);
127}
128
129static void
130_text_scroll_rev(Termpty *ty)
131{
132 Termcell *cells, *cells2 = NULL;
133 int y, start_y = 0, end_y = ty->h - 1;
134
135 if (ty->state.scroll_y2 != 0)
136 {
137 start_y = ty->state.scroll_y1;
138 end_y = ty->state.scroll_y2 - 1;
139 }
140 DBG("... scroll rev!!!!! [%i->%i]", start_y, end_y);
141 cells = &(ty->screen[end_y * ty->w]);
142 for (y = end_y; y > start_y; y--)
143 {
144 cells = &(ty->screen[(y - 1) * ty->w]);
145 cells2 = &(ty->screen[y * ty->w]);
146 _text_copy(ty, cells, cells2, ty->w);
147 }
148 _text_clear(ty, cells, ty->w, ' ', EINA_TRUE);
149}
150
151static void
152_text_scroll_test(Termpty *ty)
153{
154 int e = ty->h;
155
156 if (ty->state.scroll_y2 != 0) e = ty->state.scroll_y2;
157 if (ty->state.cy >= e)
158 {
159 _text_scroll(ty);
160 ty->state.cy = e - 1;
161 }
162}
163
164static void
165_text_scroll_rev_test(Termpty *ty)
166{
167 int b = 0;
168
169 if (ty->state.scroll_y2 != 0) b = ty->state.scroll_y1;
170 if (ty->state.cy < b)
171 {
172 _text_scroll_rev(ty);
173 ty->state.cy = b;
174 }
175}
176
177/* translates VT100 ACS escape codes to Unicode values.
178 * Based on rxvt-unicode screen.C table.
179 */
180static const int vt100_to_unicode[62] =
181{
182// ? ? ? ? ? ? ?
183// A=UPARR B=DNARR C=RTARR D=LFARR E=FLBLK F=3/4BL G=SNOMN
184 0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603,
185// H= I= J= K= L= M= N=
186 0, 0, 0, 0, 0, 0, 0,
187// O= P= Q= R= S= T= U=
188 0, 0, 0, 0, 0, 0, 0,
189// V= W= X= Y= Z= [= \=
190 0, 0, 0, 0, 0, 0, 0,
191// ? ? v->0 v->1 v->2 v->3 v->4
192// ]= ^= _=SPC `=DIAMN a=HSMED b=HT c=FF
193 0, 0, 0x0020, 0x25c6, 0x2592, 0x2409, 0x240c,
194// v->5 v->6 v->7 v->8 v->9 v->a v->b
195// d=CR e=LF f=DEGRE g=PLSMN h=NL i=VT j=SL-BR
196 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518,
197// v->c v->d v->e v->f v->10 v->11 v->12
198// k=SL-TR l=SL-TL m=SL-BL n=SL-+ o=SL-T1 p=SL-T2 q=SL-HZ
199 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, 0x23bb, 0x2500,
200// v->13 v->14 v->15 v->16 v->17 v->18 v->19
201// r=SL-T4 s=SL-T5 t=SL-VR u=SL-VL v=SL-HU w=Sl-HD x=SL-VT
202 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502,
203// v->1a v->1b b->1c v->1d v->1e/a3 v->1f
204// y=LT-EQ z=GT-EQ {=PI |=NOTEQ }=POUND ~=DOT
205 0x2264, 0x2265, 0x03c0, 0x2260, 0x20a4, 0x00b7
206};
207
208static void
209_text_append(Termpty *ty, const int *codepoints, int len)
210{
211 Termcell *cells;
212 int i, j;
213
214 cells = &(ty->screen[ty->state.cy * ty->w]);
215 for (i = 0; i < len; i++)
216 {
217 int g;
218
219 if (ty->state.wrapnext)
220 {
221 cells[ty->state.cx].att.autowrapped = 1;
222 ty->state.wrapnext = 0;
223 ty->state.cx = 0;
224 ty->state.cy++;
225 _text_scroll_test(ty);
226 cells = &(ty->screen[ty->state.cy * ty->w]);
227 }
228 if (ty->state.insert)
229 {
230 for (j = ty->w - 1; j > ty->state.cx; j--)
231 cells[j] = cells[j - 1];
232 }
233
234 g = codepoints[i];
235 switch (ty->state.charsetch)
236 {
237 case '0': /* DEC Special Character & Line Drawing Set */
238 if ((g >= 0x41) && (g <= 0x7e) &&
239 (vt100_to_unicode[g - 0x41]))
240 g = vt100_to_unicode[g - 0x41];
241 break;
242 case 'A': /* UK, replaces # with GBP */
243 if (g == '#') g = 0x20a4;
244 break;
245 default:
246 break;
247 }
248
249 cells[ty->state.cx].codepoint = g;
250 cells[ty->state.cx].att = ty->state.att;
251#if defined(SUPPORT_DBLWIDTH)
252 cells[ty->state.cx].att.dblwidth = _termpty_is_dblwidth_get(ty, g);
253 if ((cells[ty->state.cx].att.dblwidth) && (ty->state.cx < (ty->w - 1)))
254 {
255 cells[ty->state.cx + 1].codepoint = 0;
256 cells[ty->state.cx + 1].att = cells[ty->state.cx].att;
257 }
258#endif
259 if (ty->state.wrap)
260 {
261 ty->state.wrapnext = 0;
262#if defined(SUPPORT_DBLWIDTH)
263 if (cells[ty->state.cx].att.dblwidth)
264 {
265 if (ty->state.cx >= (ty->w - 2)) ty->state.wrapnext = 1;
266 else ty->state.cx += 2;
267 }
268 else
269 {
270 if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
271 else ty->state.cx++;
272 }
273#else
274 if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
275 else ty->state.cx++;
276#endif
277 }
278 else
279 {
280 ty->state.wrapnext = 0;
281 ty->state.cx++;
282#if defined(SUPPORT_DBLWIDTH)
283 if (cells[ty->state.cx].att.dblwidth)
284 {
285 ty->state.cx++;
286 if (ty->state.cx >= (ty->w - 1))
287 ty->state.cx = ty->w - 2;
288 }
289 else
290 {
291 if (ty->state.cx >= ty->w)
292 ty->state.cx = ty->w - 1;
293 }
294#else
295 if (ty->state.cx >= ty->w)
296 ty->state.cx = ty->w - 1;
297#endif
298 }
299 }
300}
301
302static void
303_term_write(Termpty *ty, const char *txt, int size)
304{
305 if (write(ty->fd, txt, size) < 0) ERR("write: %s", strerror(errno));
306}
307#define _term_txt_write(ty, txt) _term_write(ty, txt, sizeof(txt) - 1)
308
309#define CLR_END 0
310#define CLR_BEGIN 1
311#define CLR_ALL 2
312
313static void
314_clear_line(Termpty *ty, int mode, int limit)
315{
316 Termcell *cells;
317 int n = 0;
318
319 cells = &(ty->screen[ty->state.cy * ty->w]);
320 switch (mode)
321 {
322 case CLR_END:
323 n = ty->w - ty->state.cx;
324 cells = &(cells[ty->state.cx]);
325 break;
326 case CLR_BEGIN:
327 n = ty->state.cx + 1;
328 break;
329 case CLR_ALL:
330 n = ty->w;
331 break;
332 default:
333 return;
334 }
335 if (n > limit) n = limit;
336 _text_clear(ty, cells, n, 0, EINA_TRUE);
337}
338
339static void
340_clear_screen(Termpty *ty, int mode)
341{
342 Termcell *cells;
343
344 cells = ty->screen;
345 switch (mode)
346 {
347 case CLR_END:
348 _clear_line(ty, mode, ty->w);
349 if (ty->state.cy < (ty->h - 1))
350 {
351 cells = &(ty->screen[(ty->state.cy + 1) * ty->w]);
352 _text_clear(ty, cells, ty->w * (ty->h - ty->state.cy - 1), 0, EINA_TRUE);
353 }
354 break;
355 case CLR_BEGIN:
356 if (ty->state.cy > 0)
357 _text_clear(ty, cells, ty->w * ty->state.cy, 0, EINA_TRUE);
358 _clear_line(ty, mode, ty->w);
359 break;
360 case CLR_ALL:
361 _text_clear(ty, cells, ty->w * ty->h, 0, EINA_TRUE);
362 break;
363 default:
364 break;
365 }
366 if (ty->cb.cancel_sel.func)
367 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
368}
369
370static void
371_clear_all(Termpty *ty)
372{
373 if (!ty->screen) return;
374 memset(ty->screen, 0, sizeof(*(ty->screen)) * ty->w * ty->h);
375}
376
377static void
378_reset_att(Termatt *att)
379{
380 att->fg = COL_DEF;
381 att->bg = COL_DEF;
382 att->bold = 0;
383 att->faint = 0;
384#if defined(SUPPORT_ITALIC)
385 att->italic = 0;
386#elif defined(SUPPORT_DBLWIDTH)
387 att->dblwidth = 0;
388#endif
389 att->underline = 0;
390 att->blink = 0;
391 att->blink2 = 0;
392 att->inverse = 0;
393 att->invisible = 0;
394 att->strike = 0;
395 att->fg256 = 0;
396 att->bg256 = 0;
397 att->fgintense = 0;
398 att->bgintense = 0;
399 att->autowrapped = 0;
400 att->newline = 0;
401 att->tab = 0;
402}
403
404static void
405_reset_state(Termpty *ty)
406{
407 ty->state.cx = 0;
408 ty->state.cy = 0;
409 ty->state.scroll_y1 = 0;
410 ty->state.scroll_y2 = 0;
411 ty->state.had_cr_x = 0;
412 ty->state.had_cr_y = 0;
413 _reset_att(&(ty->state.att));
414 ty->state.charset = 0;
415 ty->state.charsetch = 'B';
416 ty->state.chset[0] = 'B';
417 ty->state.chset[1] = 'B';
418 ty->state.chset[2] = 'B';
419 ty->state.chset[3] = 'B';
420 ty->state.multibyte = 0;
421 ty->state.alt_kp = 0;
422 ty->state.insert = 0;
423 ty->state.appcursor = 0;
424 ty->state.wrap = 1;
425 ty->state.wrapnext = 0;
426 ty->state.hidecursor = 0;
427 ty->state.crlf = 0;
428 ty->state.had_cr = 0;
429}
430
431static void
432_cursor_copy(Termstate *state, Termstate *dest)
433{
434 dest->cx = state->cx;
435 dest->cy = state->cy;
436}
437
438static int
439_csi_arg_get(Eina_Unicode **ptr)
440{
441 Eina_Unicode *b = *ptr;
442 int octal = 0;
443 int sum = 0;
444
445 while ((*b) && (!isdigit(*b))) b++;
446 if (!*b)
447 {
448 *ptr = NULL;
449 return 0;
450 }
451 if (*b == '0') octal = 1;
452 while (isdigit(*b))
453 {
454 if (octal) sum *= 8;
455 else sum *= 10;
456 sum += *b - '0';
457 b++;
458 }
459 *ptr = b;
460 return sum;
461}
462
463static int
464_handle_esc_csi(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
465{
466 Eina_Unicode *cc;
467 int arg, first = 1, i;
468 Eina_Unicode buf[4096], *b;
469
470 cc = (Eina_Unicode *)c;
471 b = buf;
472 while ((cc < ce) && (*cc >= '0') && (*cc <= '?'))
473 {
474 *b = *cc;
475 b++;
476 cc++;
477 }
478 // if cc == ce then we got to the end of the string with no end marker
479 // so return -2 to indicate to go back to the escape beginning when
480 // there is more bufer available
481 if (cc == ce) return -2;
482 *b = 0;
483 b = buf;
484// DBG(" CSI: '%c' args '%s'", *cc, buf);
485 switch (*cc)
486 {
487 case 'm': // color set
488 while (b)
489 {
490 arg = _csi_arg_get(&b);
491 if ((first) && (!b))
492 _reset_att(&(ty->state.att));
493 else if (b)
494 {
495 first = 0;
496 switch (arg)
497 {
498 case 0: // reset to normal
499 _reset_att(&(ty->state.att));
500 break;
501 case 1: // bold/bright
502 ty->state.att.bold = 1;
503 break;
504 case 2: // faint
505 ty->state.att.faint = 1;
506 break;
507 case 3: // italic
508#if defined(SUPPORT_ITALIC)
509 ty->state.att.italic = 1;
510#endif
511 break;
512 case 4: // underline
513 ty->state.att.underline = 1;
514 break;
515 case 5: // blink
516 ty->state.att.blink = 1;
517 break;
518 case 6: // blink rapid
519 ty->state.att.blink2 = 1;
520 break;
521 case 7: // reverse
522 ty->state.att.inverse = 1;
523 break;
524 case 8: // invisible
525 ty->state.att.invisible = 1;
526 break;
527 case 9: // strikethrough
528 ty->state.att.strike = 1;
529 break;
530 case 21: // no bold/bright
531 ty->state.att.bold = 0;
532 break;
533 case 22: // no faint
534 ty->state.att.faint = 0;
535 break;
536 case 23: // no italic
537#if defined(SUPPORT_ITALIC)
538 ty->state.att.italic = 0;
539#endif
540 break;
541 case 24: // no underline
542 ty->state.att.underline = 0;
543 break;
544 case 25: // no blink
545 ty->state.att.blink = 0;
546 ty->state.att.blink2 = 0;
547 break;
548 case 27: // no reverse
549 ty->state.att.inverse = 0;
550 break;
551 case 28: // no invisible
552 ty->state.att.invisible = 0;
553 break;
554 case 29: // no strikethrough
555 ty->state.att.strike = 0;
556 break;
557 case 30: // fg
558 case 31:
559 case 32:
560 case 33:
561 case 34:
562 case 35:
563 case 36:
564 case 37:
565 ty->state.att.fg256 = 0;
566 ty->state.att.fg = (arg - 30) + COL_BLACK;
567 ty->state.att.fgintense = 0;
568 break;
569 case 38: // xterm 256 fg color ???
570 // now check if next arg is 5
571 arg = _csi_arg_get(&b);
572 if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
573 else
574 {
575 // then get next arg - should be color index 0-255
576 arg = _csi_arg_get(&b);
577 if (!b) ERR("Failed xterm 256 color fg esc val");
578 else
579 {
580 ty->state.att.fg256 = 1;
581 ty->state.att.fg = arg;
582 }
583 }
584 ty->state.att.fgintense = 0;
585 break;
586 case 39: // default fg color
587 ty->state.att.fg256 = 0;
588 ty->state.att.fg = COL_DEF;
589 ty->state.att.fgintense = 0;
590 break;
591 case 40: // bg
592 case 41:
593 case 42:
594 case 43:
595 case 44:
596 case 45:
597 case 46:
598 case 47:
599 ty->state.att.bg256 = 0;
600 ty->state.att.bg = (arg - 40) + COL_BLACK;
601 ty->state.att.bgintense = 0;
602 break;
603 case 48: // xterm 256 bg color ???
604 // now check if next arg is 5
605 arg = _csi_arg_get(&b);
606 if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
607 else
608 {
609 // then get next arg - should be color index 0-255
610 arg = _csi_arg_get(&b);
611 if (!b) ERR("Failed xterm 256 color bg esc val");
612 else
613 {
614 ty->state.att.bg256 = 1;
615 ty->state.att.bg = arg;
616 }
617 }
618 ty->state.att.bgintense = 0;
619 break;
620 case 49: // default bg color
621 ty->state.att.bg256 = 0;
622 ty->state.att.bg = COL_DEF;
623 ty->state.att.bgintense = 0;
624 break;
625 case 90: // fg
626 case 91:
627 case 92:
628 case 93:
629 case 94:
630 case 95:
631 case 96:
632 case 97:
633 ty->state.att.fg256 = 0;
634 ty->state.att.fg = (arg - 90) + COL_BLACK;
635 ty->state.att.fgintense = 1;
636 break;
637 case 98: // xterm 256 fg color ???
638 // now check if next arg is 5
639 arg = _csi_arg_get(&b);
640 if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
641 else
642 {
643 // then get next arg - should be color index 0-255
644 arg = _csi_arg_get(&b);
645 if (!b) ERR("Failed xterm 256 color fg esc val");
646 else
647 {
648 ty->state.att.fg256 = 1;
649 ty->state.att.fg = arg;
650 }
651 }
652 ty->state.att.fgintense = 1;
653 break;
654 case 99: // default fg color
655 ty->state.att.fg256 = 0;
656 ty->state.att.fg = COL_DEF;
657 ty->state.att.fgintense = 1;
658 break;
659 case 100: // bg
660 case 101:
661 case 102:
662 case 103:
663 case 104:
664 case 105:
665 case 106:
666 case 107:
667 ty->state.att.bg256 = 0;
668 ty->state.att.bg = (arg - 100) + COL_BLACK;
669 ty->state.att.bgintense = 1;
670 break;
671 case 108: // xterm 256 bg color ???
672 // now check if next arg is 5
673 arg = _csi_arg_get(&b);
674 if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
675 else
676 {
677 // then get next arg - should be color index 0-255
678 arg = _csi_arg_get(&b);
679 if (!b) ERR("Failed xterm 256 color bg esc val");
680 else
681 {
682 ty->state.att.bg256 = 1;
683 ty->state.att.bg = arg;
684 }
685 }
686 ty->state.att.bgintense = 1;
687 break;
688 case 109: // default bg color
689 ty->state.att.bg256 = 0;
690 ty->state.att.bg = COL_DEF;
691 ty->state.att.bgintense = 1;
692 break;
693 default: // not handled???
694 ERR(" color cmd [%i] not handled", arg);
695 break;
696 }
697 }
698 }
699 break;
700 case '@': // insert N blank chars
701 arg = _csi_arg_get(&b);
702 if (arg < 1) arg = 1;
703 {
704 int pi = ty->state.insert;
705 int blank[1] = { ' ' };
706 int cx = ty->state.cx;
707
708 ty->state.wrapnext = 0;
709 ty->state.insert = 1;
710 for (i = 0; i < arg; i++)
711 _text_append(ty, blank, 1);
712 ty->state.insert = pi;
713 ty->state.cx = cx;
714 }
715 break;
716 case 'A': // cursor up N
717 case 'e': // cursor up N
718 arg = _csi_arg_get(&b);
719 if (arg < 1) arg = 1;
720 ty->state.wrapnext = 0;
721 for (i = 0; i < arg; i++)
722 {
723 ty->state.cy--;
724 _text_scroll_rev_test(ty);
725 }
726 break;
727 case 'B': // cursor down N
728 arg = _csi_arg_get(&b);
729 if (arg < 1) arg = 1;
730 ty->state.wrapnext = 0;
731 for (i = 0; i < arg; i++)
732 {
733 ty->state.cy++;
734 _text_scroll_test(ty);
735 }
736 break;
737 case 'D': // cursor left N
738 arg = _csi_arg_get(&b);
739 if (arg < 1) arg = 1;
740 ty->state.wrapnext = 0;
741 for (i = 0; i < arg; i++)
742 {
743 ty->state.cx--;
744 if (ty->state.cx < 0) ty->state.cx = 0;
745 }
746 break;
747 case 'C': // cursor right N
748 case 'a': // cursor right N
749 arg = _csi_arg_get(&b);
750 if (arg < 1) arg = 1;
751 ty->state.wrapnext = 0;
752 for (i = 0; i < arg; i++)
753 {
754 ty->state.cx++;
755 if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
756 }
757 break;
758 case 'H': // cursor pos set
759 case 'f': // cursor pos set
760 ty->state.wrapnext = 0;
761 if (!*b)
762 {
763 ty->state.cx = 0;
764 ty->state.cy = 0;
765 }
766 else
767 {
768 arg = _csi_arg_get(&b);
769 if (arg < 1) arg = 1;
770 arg--;
771 if (arg < 0) arg = 0;
772 else if (arg >= ty->h) arg = ty->h - 1;
773 if (b) ty->state.cy = arg;
774 if (b)
775 {
776 arg = _csi_arg_get(&b);
777 if (arg < 1) arg = 1;
778 arg--;
779 }
780 else arg = 0;
781 if (arg < 0) arg = 0;
782 else if (arg >= ty->w) arg = ty->w - 1;
783 if (b) ty->state.cx = arg;
784 }
785 break;
786 case 'G': // to column N
787 arg = _csi_arg_get(&b);
788 if (arg < 1) arg = 1;
789 ty->state.wrapnext = 0;
790 ty->state.cx = arg - 1;
791 if (ty->state.cx < 0) ty->state.cx = 0;
792 else if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
793 break;
794 case 'd': // to row N
795 arg = _csi_arg_get(&b);
796 if (arg < 1) arg = 1;
797 ty->state.wrapnext = 0;
798 ty->state.cy = arg - 1;
799 if (ty->state.cy < 0) ty->state.cy = 0;
800 else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
801 break;
802 case 'E': // down relative N rows, and to col 0
803 arg = _csi_arg_get(&b);
804 if (arg < 1) arg = 1;
805 ty->state.wrapnext = 0;
806 ty->state.cy += arg;
807 if (ty->state.cy < 0) ty->state.cy = 0;
808 else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
809 ty->state.cx = 0;
810 break;
811 case 'F': // up relative N rows, and to col 0
812 arg = _csi_arg_get(&b);
813 if (arg < 1) arg = 1;
814 ty->state.wrapnext = 0;
815 ty->state.cy -= arg;
816 if (ty->state.cy < 0) ty->state.cy = 0;
817 else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
818 ty->state.cx = 0;
819 break;
820 case 'X': // erase N chars
821 arg = _csi_arg_get(&b);
822 if (arg < 1) arg = 1;
823 _clear_line(ty, CLR_END, arg);
824 break;
825 case 'S': // scroll up N lines
826 arg = _csi_arg_get(&b);
827 if (arg < 1) arg = 1;
828 for (i = 0; i < arg; i++) _text_scroll(ty);
829 break;
830 case 'T': // scroll down N lines
831 arg = _csi_arg_get(&b);
832 if (arg < 1) arg = 1;
833 for (i = 0; i < arg; i++) _text_scroll_rev(ty);
834 break;
835 case 'M': // delete N lines - cy
836 case 'L': // insert N lines - cy
837 arg = _csi_arg_get(&b);
838 {
839 int sy1, sy2;
840
841 sy1 = ty->state.scroll_y1;
842 sy2 = ty->state.scroll_y2;
843 if (ty->state.scroll_y2 == 0)
844 {
845 ty->state.scroll_y1 = ty->state.cy;
846 ty->state.scroll_y2 = ty->h;
847 }
848 else
849 {
850 ty->state.scroll_y1 = ty->state.cy;
851 if (ty->state.scroll_y2 <= ty->state.scroll_y1)
852 ty->state.scroll_y2 = ty->state.scroll_y1 + 1;
853 }
854 if (arg < 1) arg = 1;
855 for (i = 0; i < arg; i++)
856 {
857 if (*cc == 'M') _text_scroll(ty);
858 else _text_scroll_rev(ty);
859 }
860 ty->state.scroll_y1 = sy1;
861 ty->state.scroll_y2 = sy2;
862 }
863 break;
864 case 'P': // erase and scrollback N chars
865 arg = _csi_arg_get(&b);
866 {
867 Termcell *cells;
868 int x, lim;
869
870 if (arg < 1) arg = 1;
871 cells = &(ty->screen[ty->state.cy * ty->w]);
872 lim = ty->w - arg;
873 for (x = ty->state.cx; x < (ty->w); x++)
874 {
875 if (x < lim)
876 cells[x] = cells[x + arg];
877 else
878 memset(&(cells[x]), 0, sizeof(*cells));
879 }
880 }
881 break;
882 case 'c': // query device id
883 {
884 char bf[32];
885// 0 Base VT100, no options
886// 1 Preprocessor option (STP)
887// 2 Advanced video option (AVO)
888// 3 AVO and STP
889// 4 Graphics processor option (GO)
890// 5 GO and STP
891// 6 GO and AVO
892// 7 GO, STP, and AVO
893 snprintf(bf, sizeof(bf), "\033[?1;%ic", 0);
894 _term_write(ty, bf, strlen(bf));
895 }
896 break;
897 case 'J': // "2j" erases the screen, 1j erase from screen start to curs, 0j erase cursor to end of screen
898 arg = _csi_arg_get(&b);
899 if (b)
900 {
901 if ((arg >= CLR_END) && (arg <= CLR_ALL))
902 _clear_screen(ty, arg);
903 else
904 ERR("invalid clr scr %i", arg);
905 }
906 else _clear_screen(ty, CLR_END);
907 break;
908 case 'K': // 0K erase to end of line, 1K erase from screen start to cursor, 2K erase all of line
909 arg = _csi_arg_get(&b);
910 if (b)
911 {
912 if ((arg >= CLR_END) && (arg <= CLR_ALL))
913 _clear_line(ty, arg, ty->w);
914 else
915 ERR("invalid clr lin %i", arg);
916 }
917 else _clear_line(ty, CLR_END, ty->w);
918 break;
919 case 'h': // list - set screen mode or line wrap ("7h" == turn on line wrap, "7l" disables line wrap , ...)
920 case 'l':
921 {
922 int mode = 0, priv = 0;
923 int handled = 0;
924
925 if (*cc == 'h') mode = 1;
926 if (*b == '?')
927 {
928 priv = 1;
929 b++;
930 }
931 if (priv)
932 {
933 while (b)
934 {
935 arg = _csi_arg_get(&b);
936 if (b)
937 {
938 int size;
939
940 // complete-ish list here:
941 // http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html
942 switch (arg)
943 {
944 case 1:
945 handled = 1;
946 ty->state.appcursor = mode;
947 break;
948 case 2:
949 handled = 1;
950 ty->state.kbd_lock = mode;
951 break;
952 case 3: // should we handle this?
953 handled = 1;
954 ERR("XXX: 132 column mode %i", mode);
955 break;
956 case 4:
957 handled = 1;
958 ERR("XXX: set insert mode to %i", mode);
959 break;
960 case 5:
961 handled = 1;
962 ty->state.reverse = mode;
963 break;
964 case 6:
965 handled = 1;
966 ERR("XXX: origin mode: cursor is at 0,0/cursor limited to screen/start point for line #'s depends on top margin");
967 break;
968 case 7:
969 handled = 1;
970 DBG("DDD: set wrap mode to %i", mode);
971 ty->state.wrap = mode;
972 break;
973 case 8:
974 handled = 1;
975 ty->state.no_autorepeat = !mode;
976 INF("XXX: auto repeat %i", mode);
977 break;
978 case 9:
979 handled = 1;
980 if (mode) ty->mouse_rep = MOUSE_X10;
981 else ty->mouse_rep = MOUSE_OFF;
982 break;
983 case 12: // ignore
984 handled = 1;
985// DBG("XXX: set blinking cursor to (stop?) %i or local echo", mode);
986 break;
987 case 19: // never seen this - what to do?
988 handled = 1;
989// INF("XXX: set print extent to full screen");
990 break;
991 case 20: // crfl==1 -> cur moves to col 0 on LF, FF or VT, ==0 -> mode is cr+lf
992 handled = 1;
993 ty->state.crlf = mode;
994 break;
995 case 25:
996 handled = 1;
997 ty->state.hidecursor = !mode;
998 break;
999 case 30: // ignore
1000 handled = 1;
1001// DBG("XXX: set scrollbar mapping %i", mode);
1002 break;
1003 case 33: // ignore
1004 handled = 1;
1005// INF("XXX: Stop cursor blink %i", mode);
1006 break;
1007 case 34: // ignore
1008 handled = 1;
1009// INF("XXX: Underline cursor mode %i", mode);
1010 break;
1011 case 35: // ignore
1012 handled = 1;
1013// DBG("XXX: set shift keys %i", mode);
1014 break;
1015 case 38: // ignore
1016 handled = 1;
1017// INF("XXX: switch to tek window %i", mode);
1018 break;
1019 case 59: // ignore
1020 handled = 1;
1021// INF("XXX: kanji terminal mode %i", mode);
1022 break;
1023 case 66:
1024 handled = 1;
1025 ERR("XXX: app keypad mode %i", mode);
1026 break;
1027 case 67:
1028 handled = 1;
1029 ty->state.send_bs = mode;
1030 INF("XXX: backspace send bs not del = %i", mode);
1031 break;
1032 case 1000:
1033 handled = 1;
1034 if (mode) ty->mouse_rep = MOUSE_NORMAL;
1035 else ty->mouse_rep = MOUSE_OFF;
1036 INF("XXX: set mouse (press+release only) to %i", mode);
1037 break;
1038 case 1001:
1039 handled = 1;
1040 ERR("XXX: x11 mouse highlighting %i", mode);
1041 break;
1042 case 1002:
1043 handled = 1;
1044 ERR("XXX: set mouse (press+relese+motion while pressed) %i", mode);
1045 break;
1046 case 1003:
1047 handled = 1;
1048 ERR("XXX: set mouse (press+relese+all motion) %i", mode);
1049 break;
1050 case 1004: // i dont know what focus repporting is?
1051 handled = 1;
1052 ERR("XXX: enable focus reporting %i", mode);
1053 break;
1054 case 1005:
1055 handled = 1;
1056 if (mode) ty->mouse_rep = MOUSE_UTF8;
1057 else ty->mouse_rep = MOUSE_OFF;
1058 INF("XXX: set mouse (xterm utf8 style) %i", mode);
1059 break;
1060 case 1006:
1061 handled = 1;
1062 if (mode) ty->mouse_rep = MOUSE_SGR;
1063 else ty->mouse_rep = MOUSE_OFF;
1064 INF("XXX: set mouse (xterm sgr style) %i", mode);
1065 break;
1066 case 1010: // ignore
1067 handled = 1;
1068// DBG("XXX: set home on tty output %i", mode);
1069 break;
1070 case 1012: // ignore
1071 handled = 1;
1072// DBG("XXX: set home on tty input %i", mode);
1073 break;
1074 case 1015:
1075 handled = 1;
1076 if (mode) ty->mouse_rep = MOUSE_URXVT;
1077 else ty->mouse_rep = MOUSE_OFF;
1078 INF("XXX: set mouse (rxvt-unicdode style) %i", mode);
1079 break;
1080 case 1034: // ignore
1081 /* libreadline6 emits it but it shouldn't.
1082 See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=577012
1083 */
1084 handled = 1;
1085// DBG("Ignored screen mode %i", arg);
1086 break;
1087 case 1047:
1088 case 1049:
1089 case 47:
1090 handled = 1;
1091 DBG("DDD: switch buf");
1092 if (ty->altbuf)
1093 {
1094 // if we are looking at alt buf now,
1095 // clear main buf before we swap it back
1096 // into the sreen2 save (so save is
1097 // clear)
1098 _clear_all(ty);
1099// _cursor_copy(&(ty->swap), &(ty->state));
1100 ty->state = ty->swap;
1101 }
1102 else
1103 {
1104// _cursor_copy(&(ty->state), &(ty->swap));
1105 ty->swap = ty->state;
1106 }
1107 size = ty->w * ty->h;
1108 // swap screen content now
1109 for (i = 0; i < size; i++)
1110 {
1111 Termcell t;
1112
1113 t = ty->screen[i];
1114 ty->screen[i] = ty->screen2[i];
1115 ty->screen2[i] = t;
1116 }
1117 ty->altbuf = !ty->altbuf;
1118 if (ty->cb.cancel_sel.func)
1119 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
1120 break;
1121 case 1048:
1122 if (mode)
1123 _cursor_copy(&(ty->state), &(ty->save));
1124 else
1125 _cursor_copy(&(ty->save), &(ty->state));
1126 break;
1127 case 2004: // ignore
1128 handled = 1;
1129// INF("XXX: enable bracketed paste mode %i", mode);
1130 break;
1131 case 7727: // ignore
1132 handled = 1;
1133// INF("XXX: enable application escape mode %i", mode);
1134 break;
1135 case 7786: // ignore
1136 handled = 1;
1137// INF("XXX: enable mouse wheel -> cursor key xlation %i", mode);
1138 break;
1139 default:
1140 ERR("unhandled screen mode arg %i", arg);
1141 break;
1142 }
1143 }
1144 }
1145 }
1146 else
1147 {
1148 while (b)
1149 {
1150 arg = _csi_arg_get(&b);
1151 if (b)
1152 {
1153 if (arg == 1)
1154 {
1155 handled = 1;
1156 ty->state.appcursor = mode;
1157 }
1158 else if (arg == 4)
1159 {
1160 handled = 1;
1161 DBG("DDD: set insert mode to %i", mode);
1162 ty->state.insert = mode;
1163 }
1164// else if (arg == 24)
1165// {
1166// ERR("unhandled #24 arg %i", arg);
1167// // ???
1168// }
1169 else
1170 ERR("unhandled screen non-priv mode arg %i, mode %i, ch '%c'", arg, mode, *cc);
1171 }
1172 }
1173 }
1174 if (!handled) ERR("unhandled '%c'", *cc);
1175 }
1176 break;
1177 case 'r':
1178 arg = _csi_arg_get(&b);
1179 if (!b)
1180 {
1181 INF("no region args reset region");
1182 ty->state.scroll_y1 = 0;
1183 ty->state.scroll_y2 = 0;
1184 }
1185 else
1186 {
1187 int arg2;
1188
1189 arg2 = _csi_arg_get(&b);
1190 if (!b)
1191 {
1192 INF("failed to give 2 region args reset region");
1193 ty->state.scroll_y1 = 0;
1194 ty->state.scroll_y2 = 0;
1195 }
1196 else
1197 {
1198 if (arg > arg2)
1199 {
1200 ERR("scroll region beginning > end [%i %i]", arg, arg2);
1201 ty->state.scroll_y1 = 0;
1202 ty->state.scroll_y2 = 0;
1203 }
1204 else
1205 {
1206 INF("2 region args: %i %i", arg, arg2);
1207 if (arg >= ty->h) arg = ty->h - 1;
1208 if (arg2 > ty->h) arg2 = ty->h;
1209 arg2++;
1210 ty->state.scroll_y1 = arg - 1;
1211 ty->state.scroll_y2 = arg2 - 1;
1212 }
1213 }
1214 }
1215 break;
1216 case 's': // store cursor pos
1217 _cursor_copy(&(ty->state), &(ty->save));
1218 break;
1219 case 'u': // restore cursor pos
1220 _cursor_copy(&(ty->save), &(ty->state));
1221 break;
1222/*
1223 case 'R': // report cursor
1224 break;
1225 case 'n': // "6n" queires cursor pos, 0n, 3n, 5n too
1226 break;
1227 case 's':
1228 break;
1229 case 't':
1230 break;
1231 case 'p': // define key assignments based on keycode
1232 break;
1233 case 'q': // set/clear led's
1234 break;
1235 case 'x': // request terminal parameters
1236 break;
1237 case 'r': // set top and bottom margins
1238 break;
1239 case 'y': // invoke confidence test
1240 break;
1241 case 'g': // clear tabulation
1242 break;
1243 */
1244 default:
1245 ERR("unhandled CSI '%c' (0x%02x)", *cc, *cc);
1246 break;
1247 }
1248 cc++;
1249 return cc - c;
1250}
1251
1252static int
1253_handle_esc_xterm(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
1254{
1255 Eina_Unicode *cc;
1256 Eina_Unicode buf[4096], *b;
1257 char *s;
1258 int len = 0;
1259
1260 cc = (Eina_Unicode *)c;
1261 b = buf;
1262 while ((cc < ce) && (*cc >= ' ') && (*cc < 0x7f))
1263 {
1264 *b = *cc;
1265 b++;
1266 cc++;
1267 }
1268 *b = 0;
1269 if ((*cc < ' ') || (*cc >= 0x7f)) cc++;
1270 else return -2;
1271 switch (buf[0])
1272 {
1273 case '0':
1274 // XXX: title + name - callback
1275 s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
1276 if (ty->prop.title) eina_stringshare_del(ty->prop.title);
1277 if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
1278 if (b)
1279 {
1280 ty->prop.title = eina_stringshare_add(s);
1281 ty->prop.icon = eina_stringshare_add(s);
1282 free(s);
1283 }
1284 else
1285 {
1286 ty->prop.title = NULL;
1287 ty->prop.icon = NULL;
1288 }
1289 if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
1290 if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
1291 break;
1292 case '1':
1293 // XXX: icon name - callback
1294 s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
1295 if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
1296 if (s)
1297 {
1298 ty->prop.icon = eina_stringshare_add(s);
1299 free(s);
1300 }
1301 else
1302 {
1303 ty->prop.icon = NULL;
1304 }
1305 if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
1306 break;
1307 case '2':
1308 // XXX: title - callback
1309 s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
1310 if (ty->prop.title) eina_stringshare_del(ty->prop.title);
1311 if (s)
1312 {
1313 ty->prop.title = eina_stringshare_add(s);
1314 free(s);
1315 }
1316 else
1317 {
1318 ty->prop.title = NULL;
1319 }
1320 if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
1321 break;
1322 case '4':
1323 // XXX: set palette entry. not supported.
1324 b = &(buf[2]);
1325 break;
1326 default:
1327 // many others
1328 ERR("unhandled xterm esc '%c'", buf[0]);
1329 break;
1330 }
1331 return cc - c;
1332}
1333
1334static int
1335_handle_esc_terminology(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
1336{
1337 Eina_Unicode *cc;
1338 Eina_Unicode buf[4096], *b;
1339 char *s;
1340 int slen = 0;
1341
1342 cc = (Eina_Unicode *)c;
1343 b = buf;
1344 while ((cc < ce) && (*cc != 0x0))
1345 {
1346 *b = *cc;
1347 b++;
1348 cc++;
1349 }
1350 *b = 0;
1351 if (*cc == 0x0) cc++;
1352 else return -2;
1353 // commands are stored in the buffer, 0 bytes not allowd (end marker)
1354 s = eina_unicode_unicode_to_utf8(buf, &slen);
1355 ty->cur_cmd = s;
1356 if (ty->cb.command.func) ty->cb.command.func(ty->cb.command.data);
1357 ty->cur_cmd = NULL;
1358 if (s) free(s);
1359 return cc - c;
1360}
1361
1362static int
1363_handle_esc(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
1364{
1365 if ((ce - c) < 2) return 0;
1366 DBG("ESC: '%c'", c[1]);
1367 switch (c[1])
1368 {
1369 case '[':
1370 return 2 + _handle_esc_csi(ty, c + 2, ce);
1371 case ']':
1372 return 2 + _handle_esc_xterm(ty, c + 2, ce);
1373 case '}':
1374 return 2 + _handle_esc_terminology(ty, c + 2, ce);
1375 case '=': // set alternate keypad mode
1376 ty->state.alt_kp = 1;
1377 return 2;
1378 case '>': // set numeric keypad mode
1379 ty->state.alt_kp = 0;
1380 return 2;
1381 case 'M': // move to prev line
1382 ty->state.wrapnext = 0;
1383 ty->state.cy--;
1384 _text_scroll_rev_test(ty);
1385 return 2;
1386 case 'D': // move to next line
1387 ty->state.wrapnext = 0;
1388 ty->state.cy++;
1389 _text_scroll_test(ty);
1390 return 2;
1391 case 'E': // add \n\r
1392 ty->state.wrapnext = 0;
1393 ty->state.cx = 0;
1394 ty->state.cy++;
1395 _text_scroll_test(ty);
1396 return 2;
1397 case 'Z': // same a 'ESC [ Pn c'
1398 _term_txt_write(ty, "\033[?1;2C");
1399 return 2;
1400 case 'c': // reset terminal to initial state
1401 DBG("reset to init mode and clear");
1402 _reset_state(ty);
1403 _clear_screen(ty, CLR_ALL);
1404 if (ty->cb.cancel_sel.func)
1405 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
1406 return 2;
1407 case '(': // charset 0
1408 ty->state.chset[0] = c[2];
1409 ty->state.multibyte = 0;
1410 ty->state.charsetch = c[2];
1411 return 3;
1412 case ')': // charset 1
1413 ty->state.chset[1] = c[2];
1414 ty->state.multibyte = 0;
1415 return 3;
1416 case '*': // charset 2
1417 ty->state.chset[2] = c[2];
1418 ty->state.multibyte = 0;
1419 return 3;
1420 case '+': // charset 3
1421 ty->state.chset[3] = c[2];
1422 ty->state.multibyte = 0;
1423 return 3;
1424 case '$': // charset -2
1425 ty->state.chset[2] = c[2];
1426 ty->state.multibyte = 1;
1427 return 3;
1428 case '#': // #8 == test mode -> fill screen with "E";
1429 if (c[2] == '8')
1430 {
1431 int i, size;
1432 Termcell *cells;
1433
1434 DBG("reset to init mode and clear then fill with E");
1435 _reset_state(ty);
1436 ty->save = ty->state;
1437 ty->swap = ty->state;
1438 _clear_screen(ty, CLR_ALL);
1439 if (ty->cb.cancel_sel.func)
1440 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
1441 cells = ty->screen;
1442 size = ty->w * ty->h;
1443 if (cells)
1444 {
1445 for (i = 0; i < size; i++) cells[i].codepoint = 'E';
1446 }
1447 }
1448 return 3;
1449 case '@': // just consume this plus next char
1450 return 3;
1451 case '7': // save cursor pos
1452 _cursor_copy(&(ty->state), &(ty->save));
1453 return 2;
1454 case '8': // restore cursor pos
1455 _cursor_copy(&(ty->save), &(ty->state));
1456 return 2;
1457/*
1458 case 'G': // query gfx mode
1459 return 3;
1460 case 'H': // set tab at current column
1461 return 2;
1462 case 'n': // single shift 2
1463 return 2;
1464 case 'o': // single shift 3
1465 return 2;
1466 */
1467 default:
1468 ERR("eek - esc unhandled '%c' (0x%02x)", c[1], c[1]);
1469 break;
1470 }
1471 return 1;
1472}
1473
1474static int
1475_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce)
1476{
1477 Eina_Unicode *cc;
1478 int len = 0;
1479
1480/*
1481 printf(" B: ");
1482 int j;
1483 for (j = 0; c + j < ce && j < 100; j++)
1484 {
1485 if ((c[j] < ' ') || (c[j] >= 0x7f))
1486 printf("\033[35m%02x\033[0m", c[j]);
1487 else
1488 printf("%c", c[j]);
1489 }
1490 printf("\n");
1491 */
1492 if (c[0] < 0x20)
1493 {
1494 switch (c[0])
1495 {
1496/*
1497 case 0x00: // NUL
1498 return 1;
1499 case 0x01: // SOH (start of heading)
1500 return 1;
1501 case 0x02: // STX (start of text)
1502 return 1;
1503 case 0x03: // ETX (end of text)
1504 return 1;
1505 case 0x04: // EOT (end of transmission)
1506 return 1;
1507 */
1508 case 0x05: // ENQ (enquiry)
1509 _term_txt_write(ty, "ABC\r\n");
1510 ty->state.had_cr = 0;
1511 return 1;
1512/*
1513 case 0x06: // ACK (acknowledge)
1514 return 1;
1515 */
1516 case 0x07: // BEL '\a' (bell)
1517 if (ty->cb.bell.func) ty->cb.bell.func(ty->cb.bell.data);
1518 ty->state.had_cr = 0;
1519 return 1;
1520 case 0x08: // BS '\b' (backspace)
1521 DBG("->BS");
1522 ty->state.wrapnext = 0;
1523 ty->state.cx--;
1524 if (ty->state.cx < 0) ty->state.cx = 0;
1525 ty->state.had_cr = 0;
1526 return 1;
1527 case 0x09: // HT '\t' (horizontal tab)
1528 DBG("->HT");
1529 ty->screen[ty->state.cx + (ty->state.cy * ty->w)].att.tab = 1;
1530 ty->state.wrapnext = 0;
1531 ty->state.cx += 8;
1532 ty->state.cx = (ty->state.cx / 8) * 8;
1533 if (ty->state.cx >= ty->w)
1534 ty->state.cx = ty->w - 1;
1535 ty->state.had_cr = 0;
1536 return 1;
1537 case 0x0a: // LF '\n' (new line)
1538 case 0x0b: // VT '\v' (vertical tab)
1539 case 0x0c: // FF '\f' (form feed)
1540 DBG("->LF");
1541 if (ty->state.had_cr)
1542 ty->screen[ty->state.had_cr_x + (ty->state.had_cr_y * ty->w)].att.newline = 1;
1543 ty->state.wrapnext = 0;
1544 if (ty->state.crlf) ty->state.cx = 0;
1545 ty->state.cy++;
1546 _text_scroll_test(ty);
1547 ty->state.had_cr = 0;
1548 return 1;
1549 case 0x0d: // CR '\r' (carriage ret)
1550 DBG("->CR");
1551 if (ty->state.cx != 0)
1552 {
1553 ty->state.had_cr_x = ty->state.cx;
1554 ty->state.had_cr_y = ty->state.cy;
1555 }
1556 ty->state.wrapnext = 0;
1557 ty->state.cx = 0;
1558 ty->state.had_cr = 1;
1559 return 1;
1560
1561 case 0x0e: // SO (shift out) // Maps G1 character set into GL.
1562 ty->state.charset = 1;
1563 ty->state.charsetch = ty->state.chset[1];
1564 return 1;
1565 case 0x0f: // SI (shift in) // Maps G0 character set into GL.
1566 ty->state.charset = 0;
1567 ty->state.charsetch = ty->state.chset[0];
1568 return 1;
1569/*
1570 case 0x10: // DLE (data link escape)
1571 return 1;
1572 case 0x11: // DC1 (device control 1)
1573 return 1;
1574 case 0x12: // DC2 (device control 2)
1575 return 1;
1576 case 0x13: // DC3 (device control 3)
1577 return 1;
1578 case 0x14: // DC4 (device control 4)
1579 return 1;
1580 case 0x15: // NAK (negative ack.)
1581 return 1;
1582 case 0x16: // SYN (synchronous idle)
1583 return 1;
1584 case 0x17: // ETB (end of trans. blk)
1585 return 1;
1586 case 0x18: // CAN (cancel)
1587 return 1;
1588 case 0x19: // EM (end of medium)
1589 return 1;
1590 case 0x1a: // SUB (substitute)
1591 return 1;
1592 */
1593 case 0x1b: // ESC (escape)
1594 ty->state.had_cr = 0;
1595 return _handle_esc(ty, c, ce);
1596/*
1597 case 0x1c: // FS (file separator)
1598 return 1;
1599 case 0x1d: // GS (group separator)
1600 return 1;
1601 case 0x1e: // RS (record separator)
1602 return 1;
1603 case 0x1f: // US (unit separator)
1604 return 1;
1605 */
1606 default:
1607 ERR("unhandled char 0x%02x", c[0]);
1608 ty->state.had_cr = 0;
1609 return 1;
1610 }
1611 }
1612 else if (c[0] == 0x7f) // DEL
1613 {
1614 ERR("unhandled char 0x%02x [DEL]", c[0]);
1615 ty->state.had_cr = 0;
1616 return 1;
1617 }
1618 else if (c[0] == 0x9b) // ANSI ESC!!!
1619 {
1620 int v;
1621
1622 printf("ANSI CSI!!!!!\n");
1623 ty->state.had_cr = 0;
1624 v = _handle_esc_csi(ty, c + 1, ce);
1625 if (v == -2) return 0;
1626 return v + 1;
1627 }
1628
1629 cc = (int *)c;
1630 DBG("txt: [");
1631 while ((cc < ce) && (*cc >= 0x20) && (*cc != 0x7f))
1632 {
1633 DBG("%c", *cc);
1634 cc++;
1635 len++;
1636 }
1637 DBG("]");
1638 _text_append(ty, c, len);
1639 ty->state.had_cr = 0;
1640 return len;
1641}
1642
1643static void
1644_handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len) 48_handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
1645{ 49{
1646 Eina_Unicode *c, *ce, *b; 50 Eina_Unicode *c, *ce, *b;
@@ -1667,7 +71,7 @@ _handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
1667 ce = c + ty->buflen; 71 ce = c + ty->buflen;
1668 while (c < ce) 72 while (c < ce)
1669 { 73 {
1670 n = _handle_seq(ty, c, ce); 74 n = _termpty_handle_seq(ty, c, ce);
1671 if (n == 0) 75 if (n == 0)
1672 { 76 {
1673 Eina_Unicode *tmp = ty->buf; 77 Eina_Unicode *tmp = ty->buf;
@@ -1703,7 +107,7 @@ _handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
1703 { 107 {
1704 while (c < ce) 108 while (c < ce)
1705 { 109 {
1706 n = _handle_seq(ty, c, ce); 110 n = _termpty_handle_seq(ty, c, ce);
1707 if (n == 0) 111 if (n == 0)
1708 { 112 {
1709 bytes = ((char *)ce - (char *)c) + sizeof(Eina_Unicode); 113 bytes = ((char *)ce - (char *)c) + sizeof(Eina_Unicode);
@@ -1826,7 +230,7 @@ termpty_new(const char *cmd, int w, int h, int backscroll)
1826 ty->h = h; 230 ty->h = h;
1827 ty->backmax = backscroll; 231 ty->backmax = backscroll;
1828 232
1829 _reset_state(ty); 233 _termpty_reset_state(ty);
1830 ty->save = ty->state; 234 ty->save = ty->state;
1831 ty->swap = ty->state; 235 ty->swap = ty->state;
1832 236
@@ -2018,11 +422,11 @@ termpty_resize(Termpty *ty, int w, int h)
2018 422
2019 c1 = &(olds[y * oldw]); 423 c1 = &(olds[y * oldw]);
2020 c2 = &(ty->screen[y * ty->w]); 424 c2 = &(ty->screen[y * ty->w]);
2021 _text_copy(ty, c1, c2, ww); 425 _termpty_text_copy(ty, c1, c2, ww);
2022 426
2023 c1 = &(olds2[y * oldw]); 427 c1 = &(olds2[y * oldw]);
2024 c2 = &(ty->screen2[y * ty->w]); 428 c2 = &(ty->screen2[y * ty->w]);
2025 _text_copy(ty, c1, c2, ww); 429 _termpty_text_copy(ty, c1, c2, ww);
2026 } 430 }
2027 431
2028 free(olds); 432 free(olds);
diff --git a/src/bin/termpty.h b/src/bin/termpty.h
index 970a219..9582ef5 100644
--- a/src/bin/termpty.h
+++ b/src/bin/termpty.h
@@ -132,3 +132,5 @@ Termcell *termpty_cellrow_get(Termpty *ty, int y, int *wret);
132void termpty_write(Termpty *ty, const char *input, int len); 132void termpty_write(Termpty *ty, const char *input, int len);
133void termpty_resize(Termpty *ty, int w, int h); 133void termpty_resize(Termpty *ty, int w, int h);
134void termpty_backscroll_set(Termpty *ty, int size); 134void termpty_backscroll_set(Termpty *ty, int size);
135
136extern int _termpty_log_dom;
diff --git a/src/bin/termptyesc.c b/src/bin/termptyesc.c
new file mode 100644
index 0000000..0262470
--- /dev/null
+++ b/src/bin/termptyesc.c
@@ -0,0 +1,1224 @@
1#include "private.h"
2#include <Elementary.h>
3#include "termpty.h"
4#include "termptydbl.h"
5#include "termptyesc.h"
6#include "termptyops.h"
7#include "termptyext.h"
8
9#undef CRITICAL
10#undef ERR
11#undef WRN
12#undef INF
13#undef DBG
14
15#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
16#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
17#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
18#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
19#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
20
21static int
22_csi_arg_get(Eina_Unicode **ptr)
23{
24 Eina_Unicode *b = *ptr;
25 int octal = 0;
26 int sum = 0;
27
28 while ((*b) && (!isdigit(*b))) b++;
29 if (!*b)
30 {
31 *ptr = NULL;
32 return 0;
33 }
34 if (*b == '0') octal = 1;
35 while (isdigit(*b))
36 {
37 if (octal) sum *= 8;
38 else sum *= 10;
39 sum += *b - '0';
40 b++;
41 }
42 *ptr = b;
43 return sum;
44}
45
46static int
47_handle_esc_csi(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
48{
49 Eina_Unicode *cc;
50 int arg, first = 1, i;
51 Eina_Unicode buf[4096], *b;
52
53 cc = (Eina_Unicode *)c;
54 b = buf;
55 while ((cc < ce) && (*cc >= '0') && (*cc <= '?'))
56 {
57 *b = *cc;
58 b++;
59 cc++;
60 }
61 // if cc == ce then we got to the end of the string with no end marker
62 // so return -2 to indicate to go back to the escape beginning when
63 // there is more bufer available
64 if (cc == ce) return -2;
65 *b = 0;
66 b = buf;
67// DBG(" CSI: '%c' args '%s'", *cc, buf);
68 switch (*cc)
69 {
70 case 'm': // color set
71 while (b)
72 {
73 arg = _csi_arg_get(&b);
74 if ((first) && (!b))
75 _termpty_reset_att(&(ty->state.att));
76 else if (b)
77 {
78 first = 0;
79 switch (arg)
80 {
81 case 0: // reset to normal
82 _termpty_reset_att(&(ty->state.att));
83 break;
84 case 1: // bold/bright
85 ty->state.att.bold = 1;
86 break;
87 case 2: // faint
88 ty->state.att.faint = 1;
89 break;
90 case 3: // italic
91#if defined(SUPPORT_ITALIC)
92 ty->state.att.italic = 1;
93#endif
94 break;
95 case 4: // underline
96 ty->state.att.underline = 1;
97 break;
98 case 5: // blink
99 ty->state.att.blink = 1;
100 break;
101 case 6: // blink rapid
102 ty->state.att.blink2 = 1;
103 break;
104 case 7: // reverse
105 ty->state.att.inverse = 1;
106 break;
107 case 8: // invisible
108 ty->state.att.invisible = 1;
109 break;
110 case 9: // strikethrough
111 ty->state.att.strike = 1;
112 break;
113 case 21: // no bold/bright
114 ty->state.att.bold = 0;
115 break;
116 case 22: // no faint
117 ty->state.att.faint = 0;
118 break;
119 case 23: // no italic
120#if defined(SUPPORT_ITALIC)
121 ty->state.att.italic = 0;
122#endif
123 break;
124 case 24: // no underline
125 ty->state.att.underline = 0;
126 break;
127 case 25: // no blink
128 ty->state.att.blink = 0;
129 ty->state.att.blink2 = 0;
130 break;
131 case 27: // no reverse
132 ty->state.att.inverse = 0;
133 break;
134 case 28: // no invisible
135 ty->state.att.invisible = 0;
136 break;
137 case 29: // no strikethrough
138 ty->state.att.strike = 0;
139 break;
140 case 30: // fg
141 case 31:
142 case 32:
143 case 33:
144 case 34:
145 case 35:
146 case 36:
147 case 37:
148 ty->state.att.fg256 = 0;
149 ty->state.att.fg = (arg - 30) + COL_BLACK;
150 ty->state.att.fgintense = 0;
151 break;
152 case 38: // xterm 256 fg color ???
153 // now check if next arg is 5
154 arg = _csi_arg_get(&b);
155 if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
156 else
157 {
158 // then get next arg - should be color index 0-255
159 arg = _csi_arg_get(&b);
160 if (!b) ERR("Failed xterm 256 color fg esc val");
161 else
162 {
163 ty->state.att.fg256 = 1;
164 ty->state.att.fg = arg;
165 }
166 }
167 ty->state.att.fgintense = 0;
168 break;
169 case 39: // default fg color
170 ty->state.att.fg256 = 0;
171 ty->state.att.fg = COL_DEF;
172 ty->state.att.fgintense = 0;
173 break;
174 case 40: // bg
175 case 41:
176 case 42:
177 case 43:
178 case 44:
179 case 45:
180 case 46:
181 case 47:
182 ty->state.att.bg256 = 0;
183 ty->state.att.bg = (arg - 40) + COL_BLACK;
184 ty->state.att.bgintense = 0;
185 break;
186 case 48: // xterm 256 bg color ???
187 // now check if next arg is 5
188 arg = _csi_arg_get(&b);
189 if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
190 else
191 {
192 // then get next arg - should be color index 0-255
193 arg = _csi_arg_get(&b);
194 if (!b) ERR("Failed xterm 256 color bg esc val");
195 else
196 {
197 ty->state.att.bg256 = 1;
198 ty->state.att.bg = arg;
199 }
200 }
201 ty->state.att.bgintense = 0;
202 break;
203 case 49: // default bg color
204 ty->state.att.bg256 = 0;
205 ty->state.att.bg = COL_DEF;
206 ty->state.att.bgintense = 0;
207 break;
208 case 90: // fg
209 case 91:
210 case 92:
211 case 93:
212 case 94:
213 case 95:
214 case 96:
215 case 97:
216 ty->state.att.fg256 = 0;
217 ty->state.att.fg = (arg - 90) + COL_BLACK;
218 ty->state.att.fgintense = 1;
219 break;
220 case 98: // xterm 256 fg color ???
221 // now check if next arg is 5
222 arg = _csi_arg_get(&b);
223 if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
224 else
225 {
226 // then get next arg - should be color index 0-255
227 arg = _csi_arg_get(&b);
228 if (!b) ERR("Failed xterm 256 color fg esc val");
229 else
230 {
231 ty->state.att.fg256 = 1;
232 ty->state.att.fg = arg;
233 }
234 }
235 ty->state.att.fgintense = 1;
236 break;
237 case 99: // default fg color
238 ty->state.att.fg256 = 0;
239 ty->state.att.fg = COL_DEF;
240 ty->state.att.fgintense = 1;
241 break;
242 case 100: // bg
243 case 101:
244 case 102:
245 case 103:
246 case 104:
247 case 105:
248 case 106:
249 case 107:
250 ty->state.att.bg256 = 0;
251 ty->state.att.bg = (arg - 100) + COL_BLACK;
252 ty->state.att.bgintense = 1;
253 break;
254 case 108: // xterm 256 bg color ???
255 // now check if next arg is 5
256 arg = _csi_arg_get(&b);
257 if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
258 else
259 {
260 // then get next arg - should be color index 0-255
261 arg = _csi_arg_get(&b);
262 if (!b) ERR("Failed xterm 256 color bg esc val");
263 else
264 {
265 ty->state.att.bg256 = 1;
266 ty->state.att.bg = arg;
267 }
268 }
269 ty->state.att.bgintense = 1;
270 break;
271 case 109: // default bg color
272 ty->state.att.bg256 = 0;
273 ty->state.att.bg = COL_DEF;
274 ty->state.att.bgintense = 1;
275 break;
276 default: // not handled???
277 ERR(" color cmd [%i] not handled", arg);
278 break;
279 }
280 }
281 }
282 break;
283 case '@': // insert N blank chars
284 arg = _csi_arg_get(&b);
285 if (arg < 1) arg = 1;
286 {
287 int pi = ty->state.insert;
288 int blank[1] = { ' ' };
289 int cx = ty->state.cx;
290
291 ty->state.wrapnext = 0;
292 ty->state.insert = 1;
293 for (i = 0; i < arg; i++)
294 _termpty_text_append(ty, blank, 1);
295 ty->state.insert = pi;
296 ty->state.cx = cx;
297 }
298 break;
299 case 'A': // cursor up N
300 case 'e': // cursor up N
301 arg = _csi_arg_get(&b);
302 if (arg < 1) arg = 1;
303 ty->state.wrapnext = 0;
304 for (i = 0; i < arg; i++)
305 {
306 ty->state.cy--;
307 _termpty_text_scroll_rev_test(ty);
308 }
309 break;
310 case 'B': // cursor down N
311 arg = _csi_arg_get(&b);
312 if (arg < 1) arg = 1;
313 ty->state.wrapnext = 0;
314 for (i = 0; i < arg; i++)
315 {
316 ty->state.cy++;
317 _termpty_text_scroll_test(ty);
318 }
319 break;
320 case 'D': // cursor left N
321 arg = _csi_arg_get(&b);
322 if (arg < 1) arg = 1;
323 ty->state.wrapnext = 0;
324 for (i = 0; i < arg; i++)
325 {
326 ty->state.cx--;
327 if (ty->state.cx < 0) ty->state.cx = 0;
328 }
329 break;
330 case 'C': // cursor right N
331 case 'a': // cursor right N
332 arg = _csi_arg_get(&b);
333 if (arg < 1) arg = 1;
334 ty->state.wrapnext = 0;
335 for (i = 0; i < arg; i++)
336 {
337 ty->state.cx++;
338 if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
339 }
340 break;
341 case 'H': // cursor pos set
342 case 'f': // cursor pos set
343 ty->state.wrapnext = 0;
344 if (!*b)
345 {
346 ty->state.cx = 0;
347 ty->state.cy = 0;
348 }
349 else
350 {
351 arg = _csi_arg_get(&b);
352 if (arg < 1) arg = 1;
353 arg--;
354 if (arg < 0) arg = 0;
355 else if (arg >= ty->h) arg = ty->h - 1;
356 if (b) ty->state.cy = arg;
357 if (b)
358 {
359 arg = _csi_arg_get(&b);
360 if (arg < 1) arg = 1;
361 arg--;
362 }
363 else arg = 0;
364 if (arg < 0) arg = 0;
365 else if (arg >= ty->w) arg = ty->w - 1;
366 if (b) ty->state.cx = arg;
367 }
368 break;
369 case 'G': // to column N
370 arg = _csi_arg_get(&b);
371 if (arg < 1) arg = 1;
372 ty->state.wrapnext = 0;
373 ty->state.cx = arg - 1;
374 if (ty->state.cx < 0) ty->state.cx = 0;
375 else if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
376 break;
377 case 'd': // to row N
378 arg = _csi_arg_get(&b);
379 if (arg < 1) arg = 1;
380 ty->state.wrapnext = 0;
381 ty->state.cy = arg - 1;
382 if (ty->state.cy < 0) ty->state.cy = 0;
383 else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
384 break;
385 case 'E': // down relative N rows, and to col 0
386 arg = _csi_arg_get(&b);
387 if (arg < 1) arg = 1;
388 ty->state.wrapnext = 0;
389 ty->state.cy += arg;
390 if (ty->state.cy < 0) ty->state.cy = 0;
391 else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
392 ty->state.cx = 0;
393 break;
394 case 'F': // up relative N rows, and to col 0
395 arg = _csi_arg_get(&b);
396 if (arg < 1) arg = 1;
397 ty->state.wrapnext = 0;
398 ty->state.cy -= arg;
399 if (ty->state.cy < 0) ty->state.cy = 0;
400 else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
401 ty->state.cx = 0;
402 break;
403 case 'X': // erase N chars
404 arg = _csi_arg_get(&b);
405 if (arg < 1) arg = 1;
406 _termpty_clear_line(ty, TERMPTY_CLR_END, arg);
407 break;
408 case 'S': // scroll up N lines
409 arg = _csi_arg_get(&b);
410 if (arg < 1) arg = 1;
411 for (i = 0; i < arg; i++) _termpty_text_scroll(ty);
412 break;
413 case 'T': // scroll down N lines
414 arg = _csi_arg_get(&b);
415 if (arg < 1) arg = 1;
416 for (i = 0; i < arg; i++) _termpty_text_scroll_rev(ty);
417 break;
418 case 'M': // delete N lines - cy
419 case 'L': // insert N lines - cy
420 arg = _csi_arg_get(&b);
421 {
422 int sy1, sy2;
423
424 sy1 = ty->state.scroll_y1;
425 sy2 = ty->state.scroll_y2;
426 if (ty->state.scroll_y2 == 0)
427 {
428 ty->state.scroll_y1 = ty->state.cy;
429 ty->state.scroll_y2 = ty->h;
430 }
431 else
432 {
433 ty->state.scroll_y1 = ty->state.cy;
434 if (ty->state.scroll_y2 <= ty->state.scroll_y1)
435 ty->state.scroll_y2 = ty->state.scroll_y1 + 1;
436 }
437 if (arg < 1) arg = 1;
438 for (i = 0; i < arg; i++)
439 {
440 if (*cc == 'M') _termpty_text_scroll(ty);
441 else _termpty_text_scroll_rev(ty);
442 }
443 ty->state.scroll_y1 = sy1;
444 ty->state.scroll_y2 = sy2;
445 }
446 break;
447 case 'P': // erase and scrollback N chars
448 arg = _csi_arg_get(&b);
449 {
450 Termcell *cells;
451 int x, lim;
452
453 if (arg < 1) arg = 1;
454 cells = &(ty->screen[ty->state.cy * ty->w]);
455 lim = ty->w - arg;
456 for (x = ty->state.cx; x < (ty->w); x++)
457 {
458 if (x < lim)
459 cells[x] = cells[x + arg];
460 else
461 memset(&(cells[x]), 0, sizeof(*cells));
462 }
463 }
464 break;
465 case 'c': // query device id
466 {
467 char bf[32];
468// 0 Base VT100, no options
469// 1 Preprocessor option (STP)
470// 2 Advanced video option (AVO)
471// 3 AVO and STP
472// 4 Graphics processor option (GO)
473// 5 GO and STP
474// 6 GO and AVO
475// 7 GO, STP, and AVO
476 snprintf(bf, sizeof(bf), "\033[?1;%ic", 0);
477 termpty_write(ty, bf, strlen(bf));
478 }
479 break;
480 case 'J': // "2j" erases the screen, 1j erase from screen start to curs, 0j erase cursor to end of screen
481 arg = _csi_arg_get(&b);
482 if (b)
483 {
484 if ((arg >= TERMPTY_CLR_END) && (arg <= TERMPTY_CLR_ALL))
485 _termpty_clear_screen(ty, arg);
486 else
487 ERR("invalid clr scr %i", arg);
488 }
489 else _termpty_clear_screen(ty, TERMPTY_CLR_END);
490 break;
491 case 'K': // 0K erase to end of line, 1K erase from screen start to cursor, 2K erase all of line
492 arg = _csi_arg_get(&b);
493 if (b)
494 {
495 if ((arg >= TERMPTY_CLR_END) && (arg <= TERMPTY_CLR_ALL))
496 _termpty_clear_line(ty, arg, ty->w);
497 else
498 ERR("invalid clr lin %i", arg);
499 }
500 else _termpty_clear_line(ty, TERMPTY_CLR_END, ty->w);
501 break;
502 case 'h': // list - set screen mode or line wrap ("7h" == turn on line wrap, "7l" disables line wrap , ...)
503 case 'l':
504 {
505 int mode = 0, priv = 0;
506 int handled = 0;
507
508 if (*cc == 'h') mode = 1;
509 if (*b == '?')
510 {
511 priv = 1;
512 b++;
513 }
514 if (priv)
515 {
516 while (b)
517 {
518 arg = _csi_arg_get(&b);
519 if (b)
520 {
521 int size;
522
523 // complete-ish list here:
524 // http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html
525 switch (arg)
526 {
527 case 1:
528 handled = 1;
529 ty->state.appcursor = mode;
530 break;
531 case 2:
532 handled = 1;
533 ty->state.kbd_lock = mode;
534 break;
535 case 3: // should we handle this?
536 handled = 1;
537 ERR("XXX: 132 column mode %i", mode);
538 break;
539 case 4:
540 handled = 1;
541 ERR("XXX: set insert mode to %i", mode);
542 break;
543 case 5:
544 handled = 1;
545 ty->state.reverse = mode;
546 break;
547 case 6:
548 handled = 1;
549 ERR("XXX: origin mode: cursor is at 0,0/cursor limited to screen/start point for line #'s depends on top margin");
550 break;
551 case 7:
552 handled = 1;
553 DBG("DDD: set wrap mode to %i", mode);
554 ty->state.wrap = mode;
555 break;
556 case 8:
557 handled = 1;
558 ty->state.no_autorepeat = !mode;
559 INF("XXX: auto repeat %i", mode);
560 break;
561 case 9:
562 handled = 1;
563 if (mode) ty->mouse_rep = MOUSE_X10;
564 else ty->mouse_rep = MOUSE_OFF;
565 break;
566 case 12: // ignore
567 handled = 1;
568// DBG("XXX: set blinking cursor to (stop?) %i or local echo", mode);
569 break;
570 case 19: // never seen this - what to do?
571 handled = 1;
572// INF("XXX: set print extent to full screen");
573 break;
574 case 20: // crfl==1 -> cur moves to col 0 on LF, FF or VT, ==0 -> mode is cr+lf
575 handled = 1;
576 ty->state.crlf = mode;
577 break;
578 case 25:
579 handled = 1;
580 ty->state.hidecursor = !mode;
581 break;
582 case 30: // ignore
583 handled = 1;
584// DBG("XXX: set scrollbar mapping %i", mode);
585 break;
586 case 33: // ignore
587 handled = 1;
588// INF("XXX: Stop cursor blink %i", mode);
589 break;
590 case 34: // ignore
591 handled = 1;
592// INF("XXX: Underline cursor mode %i", mode);
593 break;
594 case 35: // ignore
595 handled = 1;
596// DBG("XXX: set shift keys %i", mode);
597 break;
598 case 38: // ignore
599 handled = 1;
600// INF("XXX: switch to tek window %i", mode);
601 break;
602 case 59: // ignore
603 handled = 1;
604// INF("XXX: kanji terminal mode %i", mode);
605 break;
606 case 66:
607 handled = 1;
608 ERR("XXX: app keypad mode %i", mode);
609 break;
610 case 67:
611 handled = 1;
612 ty->state.send_bs = mode;
613 INF("XXX: backspace send bs not del = %i", mode);
614 break;
615 case 1000:
616 handled = 1;
617 if (mode) ty->mouse_rep = MOUSE_NORMAL;
618 else ty->mouse_rep = MOUSE_OFF;
619 INF("XXX: set mouse (press+release only) to %i", mode);
620 break;
621 case 1001:
622 handled = 1;
623 ERR("XXX: x11 mouse highlighting %i", mode);
624 break;
625 case 1002:
626 handled = 1;
627 ERR("XXX: set mouse (press+relese+motion while pressed) %i", mode);
628 break;
629 case 1003:
630 handled = 1;
631 ERR("XXX: set mouse (press+relese+all motion) %i", mode);
632 break;
633 case 1004: // i dont know what focus repporting is?
634 handled = 1;
635 ERR("XXX: enable focus reporting %i", mode);
636 break;
637 case 1005:
638 handled = 1;
639 if (mode) ty->mouse_rep = MOUSE_UTF8;
640 else ty->mouse_rep = MOUSE_OFF;
641 INF("XXX: set mouse (xterm utf8 style) %i", mode);
642 break;
643 case 1006:
644 handled = 1;
645 if (mode) ty->mouse_rep = MOUSE_SGR;
646 else ty->mouse_rep = MOUSE_OFF;
647 INF("XXX: set mouse (xterm sgr style) %i", mode);
648 break;
649 case 1010: // ignore
650 handled = 1;
651// DBG("XXX: set home on tty output %i", mode);
652 break;
653 case 1012: // ignore
654 handled = 1;
655// DBG("XXX: set home on tty input %i", mode);
656 break;
657 case 1015:
658 handled = 1;
659 if (mode) ty->mouse_rep = MOUSE_URXVT;
660 else ty->mouse_rep = MOUSE_OFF;
661 INF("XXX: set mouse (rxvt-unicdode style) %i", mode);
662 break;
663 case 1034: // ignore
664 /* libreadline6 emits it but it shouldn't.
665 See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=577012
666 */
667 handled = 1;
668// DBG("Ignored screen mode %i", arg);
669 break;
670 case 1047:
671 case 1049:
672 case 47:
673 handled = 1;
674 DBG("DDD: switch buf");
675 if (ty->altbuf)
676 {
677 // if we are looking at alt buf now,
678 // clear main buf before we swap it back
679 // into the sreen2 save (so save is
680 // clear)
681 _termpty_clear_all(ty);
682// _termpty_cursor_copy(&(ty->swap), &(ty->state));
683 ty->state = ty->swap;
684 }
685 else
686 {
687// _termpty_cursor_copy(&(ty->state), &(ty->swap));
688 ty->swap = ty->state;
689 }
690 size = ty->w * ty->h;
691 // swap screen content now
692 for (i = 0; i < size; i++)
693 {
694 Termcell t;
695
696 t = ty->screen[i];
697 ty->screen[i] = ty->screen2[i];
698 ty->screen2[i] = t;
699 }
700 ty->altbuf = !ty->altbuf;
701 if (ty->cb.cancel_sel.func)
702 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
703 break;
704 case 1048:
705 if (mode)
706 _termpty_cursor_copy(&(ty->state), &(ty->save));
707 else
708 _termpty_cursor_copy(&(ty->save), &(ty->state));
709 break;
710 case 2004: // ignore
711 handled = 1;
712// INF("XXX: enable bracketed paste mode %i", mode);
713 break;
714 case 7727: // ignore
715 handled = 1;
716// INF("XXX: enable application escape mode %i", mode);
717 break;
718 case 7786: // ignore
719 handled = 1;
720// INF("XXX: enable mouse wheel -> cursor key xlation %i", mode);
721 break;
722 default:
723 ERR("unhandled screen mode arg %i", arg);
724 break;
725 }
726 }
727 }
728 }
729 else
730 {
731 while (b)
732 {
733 arg = _csi_arg_get(&b);
734 if (b)
735 {
736 if (arg == 1)
737 {
738 handled = 1;
739 ty->state.appcursor = mode;
740 }
741 else if (arg == 4)
742 {
743 handled = 1;
744 DBG("DDD: set insert mode to %i", mode);
745 ty->state.insert = mode;
746 }
747// else if (arg == 24)
748// {
749// ERR("unhandled #24 arg %i", arg);
750// // ???
751// }
752 else
753 ERR("unhandled screen non-priv mode arg %i, mode %i, ch '%c'", arg, mode, *cc);
754 }
755 }
756 }
757 if (!handled) ERR("unhandled '%c'", *cc);
758 }
759 break;
760 case 'r':
761 arg = _csi_arg_get(&b);
762 if (!b)
763 {
764 INF("no region args reset region");
765 ty->state.scroll_y1 = 0;
766 ty->state.scroll_y2 = 0;
767 }
768 else
769 {
770 int arg2;
771
772 arg2 = _csi_arg_get(&b);
773 if (!b)
774 {
775 INF("failed to give 2 region args reset region");
776 ty->state.scroll_y1 = 0;
777 ty->state.scroll_y2 = 0;
778 }
779 else
780 {
781 if (arg > arg2)
782 {
783 ERR("scroll region beginning > end [%i %i]", arg, arg2);
784 ty->state.scroll_y1 = 0;
785 ty->state.scroll_y2 = 0;
786 }
787 else
788 {
789 INF("2 region args: %i %i", arg, arg2);
790 if (arg >= ty->h) arg = ty->h - 1;
791 if (arg2 > ty->h) arg2 = ty->h;
792 arg2++;
793 ty->state.scroll_y1 = arg - 1;
794 ty->state.scroll_y2 = arg2 - 1;
795 }
796 }
797 }
798 break;
799 case 's': // store cursor pos
800 _termpty_cursor_copy(&(ty->state), &(ty->save));
801 break;
802 case 'u': // restore cursor pos
803 _termpty_cursor_copy(&(ty->save), &(ty->state));
804 break;
805/*
806 case 'R': // report cursor
807 break;
808 case 'n': // "6n" queires cursor pos, 0n, 3n, 5n too
809 break;
810 case 's':
811 break;
812 case 't':
813 break;
814 case 'p': // define key assignments based on keycode
815 break;
816 case 'q': // set/clear led's
817 break;
818 case 'x': // request terminal parameters
819 break;
820 case 'r': // set top and bottom margins
821 break;
822 case 'y': // invoke confidence test
823 break;
824 case 'g': // clear tabulation
825 break;
826 */
827 default:
828 ERR("unhandled CSI '%c' (0x%02x)", *cc, *cc);
829 break;
830 }
831 cc++;
832 return cc - c;
833}
834
835static int
836_handle_esc_xterm(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
837{
838 Eina_Unicode *cc;
839 Eina_Unicode buf[4096], *b;
840 char *s;
841 int len = 0;
842
843 cc = (Eina_Unicode *)c;
844 b = buf;
845 while ((cc < ce) && (*cc >= ' ') && (*cc < 0x7f))
846 {
847 *b = *cc;
848 b++;
849 cc++;
850 }
851 *b = 0;
852 if ((*cc < ' ') || (*cc >= 0x7f)) cc++;
853 else return -2;
854 switch (buf[0])
855 {
856 case '0':
857 // XXX: title + name - callback
858 s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
859 if (ty->prop.title) eina_stringshare_del(ty->prop.title);
860 if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
861 if (b)
862 {
863 ty->prop.title = eina_stringshare_add(s);
864 ty->prop.icon = eina_stringshare_add(s);
865 free(s);
866 }
867 else
868 {
869 ty->prop.title = NULL;
870 ty->prop.icon = NULL;
871 }
872 if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
873 if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
874 break;
875 case '1':
876 // XXX: icon name - callback
877 s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
878 if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
879 if (s)
880 {
881 ty->prop.icon = eina_stringshare_add(s);
882 free(s);
883 }
884 else
885 {
886 ty->prop.icon = NULL;
887 }
888 if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
889 break;
890 case '2':
891 // XXX: title - callback
892 s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
893 if (ty->prop.title) eina_stringshare_del(ty->prop.title);
894 if (s)
895 {
896 ty->prop.title = eina_stringshare_add(s);
897 free(s);
898 }
899 else
900 {
901 ty->prop.title = NULL;
902 }
903 if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
904 break;
905 case '4':
906 // XXX: set palette entry. not supported.
907 b = &(buf[2]);
908 break;
909 default:
910 // many others
911 ERR("unhandled xterm esc '%c'", buf[0]);
912 break;
913 }
914 return cc - c;
915}
916
917static int
918_handle_esc_terminology(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
919{
920 Eina_Unicode *cc;
921 Eina_Unicode buf[4096], *b;
922 char *s;
923 int slen = 0;
924
925 cc = (Eina_Unicode *)c;
926 b = buf;
927 while ((cc < ce) && (*cc != 0x0))
928 {
929 *b = *cc;
930 b++;
931 cc++;
932 }
933 *b = 0;
934 if (*cc == 0x0) cc++;
935 else return -2;
936 // commands are stored in the buffer, 0 bytes not allowd (end marker)
937 s = eina_unicode_unicode_to_utf8(buf, &slen);
938 ty->cur_cmd = s;
939 if (ty->cb.command.func) ty->cb.command.func(ty->cb.command.data);
940 ty->cur_cmd = NULL;
941 if (s) free(s);
942 return cc - c;
943}
944
945static int
946_handle_esc(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
947{
948 if ((ce - c) < 2) return 0;
949 DBG("ESC: '%c'", c[1]);
950 switch (c[1])
951 {
952 case '[':
953 return 2 + _handle_esc_csi(ty, c + 2, ce);
954 case ']':
955 return 2 + _handle_esc_xterm(ty, c + 2, ce);
956 case '}':
957 return 2 + _handle_esc_terminology(ty, c + 2, ce);
958 case '=': // set alternate keypad mode
959 ty->state.alt_kp = 1;
960 return 2;
961 case '>': // set numeric keypad mode
962 ty->state.alt_kp = 0;
963 return 2;
964 case 'M': // move to prev line
965 ty->state.wrapnext = 0;
966 ty->state.cy--;
967 _termpty_text_scroll_rev_test(ty);
968 return 2;
969 case 'D': // move to next line
970 ty->state.wrapnext = 0;
971 ty->state.cy++;
972 _termpty_text_scroll_test(ty);
973 return 2;
974 case 'E': // add \n\r
975 ty->state.wrapnext = 0;
976 ty->state.cx = 0;
977 ty->state.cy++;
978 _termpty_text_scroll_test(ty);
979 return 2;
980 case 'Z': // same a 'ESC [ Pn c'
981 _term_txt_write(ty, "\033[?1;2C");
982 return 2;
983 case 'c': // reset terminal to initial state
984 DBG("reset to init mode and clear");
985 _termpty_reset_state(ty);
986 _termpty_clear_screen(ty, TERMPTY_CLR_ALL);
987 if (ty->cb.cancel_sel.func)
988 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
989 return 2;
990 case '(': // charset 0
991 ty->state.chset[0] = c[2];
992 ty->state.multibyte = 0;
993 ty->state.charsetch = c[2];
994 return 3;
995 case ')': // charset 1
996 ty->state.chset[1] = c[2];
997 ty->state.multibyte = 0;
998 return 3;
999 case '*': // charset 2
1000 ty->state.chset[2] = c[2];
1001 ty->state.multibyte = 0;
1002 return 3;
1003 case '+': // charset 3
1004 ty->state.chset[3] = c[2];
1005 ty->state.multibyte = 0;
1006 return 3;
1007 case '$': // charset -2
1008 ty->state.chset[2] = c[2];
1009 ty->state.multibyte = 1;
1010 return 3;
1011 case '#': // #8 == test mode -> fill screen with "E";
1012 if (c[2] == '8')
1013 {
1014 int i, size;
1015 Termcell *cells;
1016
1017 DBG("reset to init mode and clear then fill with E");
1018 _termpty_reset_state(ty);
1019 ty->save = ty->state;
1020 ty->swap = ty->state;
1021 _termpty_clear_screen(ty, TERMPTY_CLR_ALL);
1022 if (ty->cb.cancel_sel.func)
1023 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
1024 cells = ty->screen;
1025 size = ty->w * ty->h;
1026 if (cells)
1027 {
1028 for (i = 0; i < size; i++) cells[i].codepoint = 'E';
1029 }
1030 }
1031 return 3;
1032 case '@': // just consume this plus next char
1033 return 3;
1034 case '7': // save cursor pos
1035 _termpty_cursor_copy(&(ty->state), &(ty->save));
1036 return 2;
1037 case '8': // restore cursor pos
1038 _termpty_cursor_copy(&(ty->save), &(ty->state));
1039 return 2;
1040/*
1041 case 'G': // query gfx mode
1042 return 3;
1043 case 'H': // set tab at current column
1044 return 2;
1045 case 'n': // single shift 2
1046 return 2;
1047 case 'o': // single shift 3
1048 return 2;
1049 */
1050 default:
1051 ERR("eek - esc unhandled '%c' (0x%02x)", c[1], c[1]);
1052 break;
1053 }
1054 return 1;
1055}
1056
1057int
1058_termpty_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce)
1059{
1060 Eina_Unicode *cc;
1061 int len = 0;
1062
1063/*
1064 printf(" B: ");
1065 int j;
1066 for (j = 0; c + j < ce && j < 100; j++)
1067 {
1068 if ((c[j] < ' ') || (c[j] >= 0x7f))
1069 printf("\033[35m%02x\033[0m", c[j]);
1070 else
1071 printf("%c", c[j]);
1072 }
1073 printf("\n");
1074 */
1075 if (c[0] < 0x20)
1076 {
1077 switch (c[0])
1078 {
1079/*
1080 case 0x00: // NUL
1081 return 1;
1082 case 0x01: // SOH (start of heading)
1083 return 1;
1084 case 0x02: // STX (start of text)
1085 return 1;
1086 case 0x03: // ETX (end of text)
1087 return 1;
1088 case 0x04: // EOT (end of transmission)
1089 return 1;
1090 */
1091 case 0x05: // ENQ (enquiry)
1092 _term_txt_write(ty, "ABC\r\n");
1093 ty->state.had_cr = 0;
1094 return 1;
1095/*
1096 case 0x06: // ACK (acknowledge)
1097 return 1;
1098 */
1099 case 0x07: // BEL '\a' (bell)
1100 if (ty->cb.bell.func) ty->cb.bell.func(ty->cb.bell.data);
1101 ty->state.had_cr = 0;
1102 return 1;
1103 case 0x08: // BS '\b' (backspace)
1104 DBG("->BS");
1105 ty->state.wrapnext = 0;
1106 ty->state.cx--;
1107 if (ty->state.cx < 0) ty->state.cx = 0;
1108 ty->state.had_cr = 0;
1109 return 1;
1110 case 0x09: // HT '\t' (horizontal tab)
1111 DBG("->HT");
1112 ty->screen[ty->state.cx + (ty->state.cy * ty->w)].att.tab = 1;
1113 ty->state.wrapnext = 0;
1114 ty->state.cx += 8;
1115 ty->state.cx = (ty->state.cx / 8) * 8;
1116 if (ty->state.cx >= ty->w)
1117 ty->state.cx = ty->w - 1;
1118 ty->state.had_cr = 0;
1119 return 1;
1120 case 0x0a: // LF '\n' (new line)
1121 case 0x0b: // VT '\v' (vertical tab)
1122 case 0x0c: // FF '\f' (form feed)
1123 DBG("->LF");
1124 if (ty->state.had_cr)
1125 ty->screen[ty->state.had_cr_x + (ty->state.had_cr_y * ty->w)].att.newline = 1;
1126 ty->state.wrapnext = 0;
1127 if (ty->state.crlf) ty->state.cx = 0;
1128 ty->state.cy++;
1129 _termpty_text_scroll_test(ty);
1130 ty->state.had_cr = 0;
1131 return 1;
1132 case 0x0d: // CR '\r' (carriage ret)
1133 DBG("->CR");
1134 if (ty->state.cx != 0)
1135 {
1136 ty->state.had_cr_x = ty->state.cx;
1137 ty->state.had_cr_y = ty->state.cy;
1138 }
1139 ty->state.wrapnext = 0;
1140 ty->state.cx = 0;
1141 ty->state.had_cr = 1;
1142 return 1;
1143
1144 case 0x0e: // SO (shift out) // Maps G1 character set into GL.
1145 ty->state.charset = 1;
1146 ty->state.charsetch = ty->state.chset[1];
1147 return 1;
1148 case 0x0f: // SI (shift in) // Maps G0 character set into GL.
1149 ty->state.charset = 0;
1150 ty->state.charsetch = ty->state.chset[0];
1151 return 1;
1152/*
1153 case 0x10: // DLE (data link escape)
1154 return 1;
1155 case 0x11: // DC1 (device control 1)
1156 return 1;
1157 case 0x12: // DC2 (device control 2)
1158 return 1;
1159 case 0x13: // DC3 (device control 3)
1160 return 1;
1161 case 0x14: // DC4 (device control 4)
1162 return 1;
1163 case 0x15: // NAK (negative ack.)
1164 return 1;
1165 case 0x16: // SYN (synchronous idle)
1166 return 1;
1167 case 0x17: // ETB (end of trans. blk)
1168 return 1;
1169 case 0x18: // CAN (cancel)
1170 return 1;
1171 case 0x19: // EM (end of medium)
1172 return 1;
1173 case 0x1a: // SUB (substitute)
1174 return 1;
1175 */
1176 case 0x1b: // ESC (escape)
1177 ty->state.had_cr = 0;
1178 return _handle_esc(ty, c, ce);
1179/*
1180 case 0x1c: // FS (file separator)
1181 return 1;
1182 case 0x1d: // GS (group separator)
1183 return 1;
1184 case 0x1e: // RS (record separator)
1185 return 1;
1186 case 0x1f: // US (unit separator)
1187 return 1;
1188 */
1189 default:
1190 ERR("unhandled char 0x%02x", c[0]);
1191 ty->state.had_cr = 0;
1192 return 1;
1193 }
1194 }
1195 else if (c[0] == 0x7f) // DEL
1196 {
1197 ERR("unhandled char 0x%02x [DEL]", c[0]);
1198 ty->state.had_cr = 0;
1199 return 1;
1200 }
1201 else if (c[0] == 0x9b) // ANSI ESC!!!
1202 {
1203 int v;
1204
1205 printf("ANSI CSI!!!!!\n");
1206 ty->state.had_cr = 0;
1207 v = _handle_esc_csi(ty, c + 1, ce);
1208 if (v == -2) return 0;
1209 return v + 1;
1210 }
1211
1212 cc = (int *)c;
1213 DBG("txt: [");
1214 while ((cc < ce) && (*cc >= 0x20) && (*cc != 0x7f))
1215 {
1216 DBG("%c", *cc);
1217 cc++;
1218 len++;
1219 }
1220 DBG("]");
1221 _termpty_text_append(ty, c, len);
1222 ty->state.had_cr = 0;
1223 return len;
1224}
diff --git a/src/bin/termptyesc.h b/src/bin/termptyesc.h
new file mode 100644
index 0000000..c72cf55
--- /dev/null
+++ b/src/bin/termptyesc.h
@@ -0,0 +1,2 @@
1int _termpty_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce);
2
diff --git a/src/bin/termptyext.c b/src/bin/termptyext.c
new file mode 100644
index 0000000..aef259a
--- /dev/null
+++ b/src/bin/termptyext.c
@@ -0,0 +1,61 @@
1#include "private.h"
2#include <Elementary.h>
3#include "termpty.h"
4#include "termptyops.h"
5
6#undef CRITICAL
7#undef ERR
8#undef WRN
9#undef INF
10#undef DBG
11
12#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
13#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
14#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
15#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
16#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
17
18//// extended terminology escape handling goes in here
19//
20// this is where escapes get handled *IF* the termpty layer needs to interpret
21// them itself for some reason. if it returns EINA_FALSE, it means the escape
22// is to be passed onto termio layer as a callback and handled there after
23// this code. an extended escape may be handled in here exclusively (return
24// EINA_TRUE), handled here first, then in termio (EINA_FALSE return) or not
25// handled here at all and just passed to termio to figure it out (return
26// EINA_FALSE).
27//
28// command strings like like this:
29// axBLAHBLAH
30// where 'a' is the major opcode char.
31// and 'x' is the minor opcode char.
32// and 'BLAHBLAH' is an optional data payload string
33
34static Eina_Bool
35_handle_op_a(Termpty *ty __UNUSED__, const char *txt, Eina_Unicode *utxt __UNUSED__)
36{
37 switch (txt[1])
38 {
39 case 'a': // command aa*
40 break;
41 // room here for more minor opcode chars like 'b', 'c' etc.
42 default:
43 break;
44 }
45 return EINA_FALSE;
46}
47
48Eina_Bool
49_termpty_ext_handle(Termpty *ty, const char *txt, Eina_Unicode *utxt)
50{
51 switch (txt[0]) // major opcode
52 {
53 case 'a': // command a*
54 return _handle_op_a(ty, txt, utxt);
55 break;
56 // room here for more major opcode chars like 'b', 'c' etc.
57 default:
58 break;
59 }
60 return EINA_FALSE;
61}
diff --git a/src/bin/termptyext.h b/src/bin/termptyext.h
new file mode 100644
index 0000000..95bc894
--- /dev/null
+++ b/src/bin/termptyext.h
@@ -0,0 +1,2 @@
1Eina_Bool _termpty_ext_handle(Termpty *ty, const char *txt, Eina_Unicode *utxt);
2
diff --git a/src/bin/termptygfx.c b/src/bin/termptygfx.c
new file mode 100644
index 0000000..3a6a607
--- /dev/null
+++ b/src/bin/termptygfx.c
@@ -0,0 +1,53 @@
1#include "private.h"
2#include <Elementary.h>
3#include "termptygfx.h"
4
5/* translates VT100 ACS escape codes to Unicode values.
6 * Based on rxvt-unicode screen.C table.
7 */
8static const unsigned short vt100_to_unicode[62] =
9{
10// ? ? ? ? ? ? ?
11// A=UPARR B=DNARR C=RTARR D=LFARR E=FLBLK F=3/4BL G=SNOMN
12 0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603,
13// H= I= J= K= L= M= N=
14 0, 0, 0, 0, 0, 0, 0,
15// O= P= Q= R= S= T= U=
16 0, 0, 0, 0, 0, 0, 0,
17// V= W= X= Y= Z= [= \=
18 0, 0, 0, 0, 0, 0, 0,
19// ? ? v->0 v->1 v->2 v->3 v->4
20// ]= ^= _=SPC `=DIAMN a=HSMED b=HT c=FF
21 0, 0, 0x0020, 0x25c6, 0x2592, 0x2409, 0x240c,
22// v->5 v->6 v->7 v->8 v->9 v->a v->b
23// d=CR e=LF f=DEGRE g=PLSMN h=NL i=VT j=SL-BR
24 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518,
25// v->c v->d v->e v->f v->10 v->11 v->12
26// k=SL-TR l=SL-TL m=SL-BL n=SL-+ o=SL-T1 p=SL-T2 q=SL-HZ
27 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, 0x23bb, 0x2500,
28// v->13 v->14 v->15 v->16 v->17 v->18 v->19
29// r=SL-T4 s=SL-T5 t=SL-VR u=SL-VL v=SL-HU w=Sl-HD x=SL-VT
30 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502,
31// v->1a v->1b b->1c v->1d v->1e/a3 v->1f
32// y=LT-EQ z=GT-EQ {=PI |=NOTEQ }=POUND ~=DOT
33 0x2264, 0x2265, 0x03c0, 0x2260, 0x20a4, 0x00b7
34};
35
36Eina_Unicode
37_termpty_charset_trans(Eina_Unicode g, int chset)
38{
39 switch (chset)
40 {
41 case '0': /* DEC Special Character & Line Drawing Set */
42 if ((g >= 0x41) && (g <= 0x7e) &&
43 (vt100_to_unicode[g - 0x41]))
44 return vt100_to_unicode[g - 0x41];
45 break;
46 case 'A': /* UK, replaces # with GBP */
47 if (g == '#') return 0x20a4;
48 break;
49 default:
50 break;
51 }
52 return g;
53}
diff --git a/src/bin/termptygfx.h b/src/bin/termptygfx.h
new file mode 100644
index 0000000..e44efbd
--- /dev/null
+++ b/src/bin/termptygfx.h
@@ -0,0 +1,2 @@
1Eina_Unicode _termpty_charset_trans(Eina_Unicode g, int chset);
2
diff --git a/src/bin/termptyops.c b/src/bin/termptyops.c
new file mode 100644
index 0000000..d7c2dbc
--- /dev/null
+++ b/src/bin/termptyops.c
@@ -0,0 +1,354 @@
1#include "private.h"
2#include <Elementary.h>
3#include "termpty.h"
4#include "termptydbl.h"
5#include "termptyops.h"
6#include "termptygfx.h"
7
8#undef CRITICAL
9#undef ERR
10#undef WRN
11#undef INF
12#undef DBG
13
14#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
15#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
16#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
17#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
18#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
19
20static void
21_text_clear(Termpty *ty, Termcell *cells, int count, int val, Eina_Bool inherit_att)
22{
23 int i;
24 Termatt clear;
25
26 memset(&clear, 0, sizeof(clear));
27 if (inherit_att)
28 {
29 for (i = 0; i < count; i++)
30 {
31 cells[i].codepoint = val;
32 cells[i].att = ty->state.att;
33 }
34 }
35 else
36 {
37 for (i = 0; i < count; i++)
38 {
39 cells[i].codepoint = val;
40 cells[i].att = clear;
41 }
42 }
43}
44
45static void
46_text_save_top(Termpty *ty)
47{
48 Termsave *ts;
49
50 if (ty->backmax <= 0) return;
51 ts = malloc(sizeof(Termsave) + ((ty->w - 1) * sizeof(Termcell)));
52 ts->w = ty->w;
53 _termpty_text_copy(ty, ty->screen, ts->cell, ty->w);
54 if (!ty->back) ty->back = calloc(1, sizeof(Termsave *) * ty->backmax);
55 if (ty->back[ty->backpos]) free(ty->back[ty->backpos]);
56 ty->back[ty->backpos] = ts;
57 ty->backpos++;
58 if (ty->backpos >= ty->backmax) ty->backpos = 0;
59 ty->backscroll_num++;
60 if (ty->backscroll_num >= ty->backmax) ty->backscroll_num = ty->backmax - 1;
61}
62
63void
64_termpty_text_copy(Termpty *ty __UNUSED__, Termcell *cells, Termcell *dest, int count)
65{
66 memcpy(dest, cells, sizeof(*(cells)) * count);
67}
68
69void
70_termpty_text_scroll(Termpty *ty)
71{
72 Termcell *cells = NULL, *cells2;
73 int y, start_y = 0, end_y = ty->h - 1;
74
75 if (ty->state.scroll_y2 != 0)
76 {
77 start_y = ty->state.scroll_y1;
78 end_y = ty->state.scroll_y2 - 1;
79 }
80 else
81 {
82 if (!ty->altbuf)
83 {
84 _text_save_top(ty);
85 if (ty->cb.scroll.func) ty->cb.scroll.func(ty->cb.scroll.data);
86 }
87 else
88 if (ty->cb.cancel_sel.func)
89 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
90 }
91 DBG("... scroll!!!!! [%i->%i]", start_y, end_y);
92 cells2 = &(ty->screen[end_y * ty->w]);
93 for (y = start_y; y < end_y; y++)
94 {
95 cells = &(ty->screen[y * ty->w]);
96 cells2 = &(ty->screen[(y + 1) * ty->w]);
97 _termpty_text_copy(ty, cells2, cells, ty->w);
98 }
99 _text_clear(ty, cells2, ty->w, ' ', EINA_TRUE);
100}
101
102void
103_termpty_text_scroll_rev(Termpty *ty)
104{
105 Termcell *cells, *cells2 = NULL;
106 int y, start_y = 0, end_y = ty->h - 1;
107
108 if (ty->state.scroll_y2 != 0)
109 {
110 start_y = ty->state.scroll_y1;
111 end_y = ty->state.scroll_y2 - 1;
112 }
113 DBG("... scroll rev!!!!! [%i->%i]", start_y, end_y);
114 cells = &(ty->screen[end_y * ty->w]);
115 for (y = end_y; y > start_y; y--)
116 {
117 cells = &(ty->screen[(y - 1) * ty->w]);
118 cells2 = &(ty->screen[y * ty->w]);
119 _termpty_text_copy(ty, cells, cells2, ty->w);
120 }
121 _text_clear(ty, cells, ty->w, ' ', EINA_TRUE);
122}
123
124void
125_termpty_text_scroll_test(Termpty *ty)
126{
127 int e = ty->h;
128
129 if (ty->state.scroll_y2 != 0) e = ty->state.scroll_y2;
130 if (ty->state.cy >= e)
131 {
132 _termpty_text_scroll(ty);
133 ty->state.cy = e - 1;
134 }
135}
136
137void
138_termpty_text_scroll_rev_test(Termpty *ty)
139{
140 int b = 0;
141
142 if (ty->state.scroll_y2 != 0) b = ty->state.scroll_y1;
143 if (ty->state.cy < b)
144 {
145 _termpty_text_scroll_rev(ty);
146 ty->state.cy = b;
147 }
148}
149
150void
151_termpty_text_append(Termpty *ty, const Eina_Unicode *codepoints, int len)
152{
153 Termcell *cells;
154 int i, j;
155
156 cells = &(ty->screen[ty->state.cy * ty->w]);
157 for (i = 0; i < len; i++)
158 {
159 Eina_Unicode g;
160
161 if (ty->state.wrapnext)
162 {
163 cells[ty->state.cx].att.autowrapped = 1;
164 ty->state.wrapnext = 0;
165 ty->state.cx = 0;
166 ty->state.cy++;
167 _termpty_text_scroll_test(ty);
168 cells = &(ty->screen[ty->state.cy * ty->w]);
169 }
170 if (ty->state.insert)
171 {
172 for (j = ty->w - 1; j > ty->state.cx; j--)
173 cells[j] = cells[j - 1];
174 }
175
176 g = _termpty_charset_trans(codepoints[i], ty->state.charsetch);
177
178 cells[ty->state.cx].codepoint = g;
179 cells[ty->state.cx].att = ty->state.att;
180#if defined(SUPPORT_DBLWIDTH)
181 cells[ty->state.cx].att.dblwidth = _termpty_is_dblwidth_get(ty, g);
182 if ((cells[ty->state.cx].att.dblwidth) && (ty->state.cx < (ty->w - 1)))
183 {
184 cells[ty->state.cx + 1].codepoint = 0;
185 cells[ty->state.cx + 1].att = cells[ty->state.cx].att;
186 }
187#endif
188 if (ty->state.wrap)
189 {
190 ty->state.wrapnext = 0;
191#if defined(SUPPORT_DBLWIDTH)
192 if (cells[ty->state.cx].att.dblwidth)
193 {
194 if (ty->state.cx >= (ty->w - 2)) ty->state.wrapnext = 1;
195 else ty->state.cx += 2;
196 }
197 else
198 {
199 if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
200 else ty->state.cx++;
201 }
202#else
203 if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
204 else ty->state.cx++;
205#endif
206 }
207 else
208 {
209 ty->state.wrapnext = 0;
210 ty->state.cx++;
211#if defined(SUPPORT_DBLWIDTH)
212 if (cells[ty->state.cx].att.dblwidth)
213 {
214 ty->state.cx++;
215 if (ty->state.cx >= (ty->w - 1))
216 ty->state.cx = ty->w - 2;
217 }
218 else
219 {
220 if (ty->state.cx >= ty->w)
221 ty->state.cx = ty->w - 1;
222 }
223#else
224 if (ty->state.cx >= ty->w)
225 ty->state.cx = ty->w - 1;
226#endif
227 }
228 }
229}
230
231void
232_termpty_clear_line(Termpty *ty, Termpty_Clear mode, int limit)
233{
234 Termcell *cells;
235 int n = 0;
236
237 cells = &(ty->screen[ty->state.cy * ty->w]);
238 switch (mode)
239 {
240 case TERMPTY_CLR_END:
241 n = ty->w - ty->state.cx;
242 cells = &(cells[ty->state.cx]);
243 break;
244 case TERMPTY_CLR_BEGIN:
245 n = ty->state.cx + 1;
246 break;
247 case TERMPTY_CLR_ALL:
248 n = ty->w;
249 break;
250 default:
251 return;
252 }
253 if (n > limit) n = limit;
254 _text_clear(ty, cells, n, 0, EINA_TRUE);
255}
256
257void
258_termpty_clear_screen(Termpty *ty, Termpty_Clear mode)
259{
260 Termcell *cells;
261
262 cells = ty->screen;
263 switch (mode)
264 {
265 case TERMPTY_CLR_END:
266 _termpty_clear_line(ty, mode, ty->w);
267 if (ty->state.cy < (ty->h - 1))
268 {
269 cells = &(ty->screen[(ty->state.cy + 1) * ty->w]);
270 _text_clear(ty, cells, ty->w * (ty->h - ty->state.cy - 1), 0, EINA_TRUE);
271 }
272 break;
273 case TERMPTY_CLR_BEGIN:
274 if (ty->state.cy > 0)
275 _text_clear(ty, cells, ty->w * ty->state.cy, 0, EINA_TRUE);
276 _termpty_clear_line(ty, mode, ty->w);
277 break;
278 case TERMPTY_CLR_ALL:
279 _text_clear(ty, cells, ty->w * ty->h, 0, EINA_TRUE);
280 break;
281 default:
282 break;
283 }
284 if (ty->cb.cancel_sel.func)
285 ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
286}
287
288void
289_termpty_clear_all(Termpty *ty)
290{
291 if (!ty->screen) return;
292 memset(ty->screen, 0, sizeof(*(ty->screen)) * ty->w * ty->h);
293}
294
295void
296_termpty_reset_att(Termatt *att)
297{
298 att->fg = COL_DEF;
299 att->bg = COL_DEF;
300 att->bold = 0;
301 att->faint = 0;
302#if defined(SUPPORT_ITALIC)
303 att->italic = 0;
304#elif defined(SUPPORT_DBLWIDTH)
305 att->dblwidth = 0;
306#endif
307 att->underline = 0;
308 att->blink = 0;
309 att->blink2 = 0;
310 att->inverse = 0;
311 att->invisible = 0;
312 att->strike = 0;
313 att->fg256 = 0;
314 att->bg256 = 0;
315 att->fgintense = 0;
316 att->bgintense = 0;
317 att->autowrapped = 0;
318 att->newline = 0;
319 att->tab = 0;
320}
321
322void
323_termpty_reset_state(Termpty *ty)
324{
325 ty->state.cx = 0;
326 ty->state.cy = 0;
327 ty->state.scroll_y1 = 0;
328 ty->state.scroll_y2 = 0;
329 ty->state.had_cr_x = 0;
330 ty->state.had_cr_y = 0;
331 _termpty_reset_att(&(ty->state.att));
332 ty->state.charset = 0;
333 ty->state.charsetch = 'B';
334 ty->state.chset[0] = 'B';
335 ty->state.chset[1] = 'B';
336 ty->state.chset[2] = 'B';
337 ty->state.chset[3] = 'B';
338 ty->state.multibyte = 0;
339 ty->state.alt_kp = 0;
340 ty->state.insert = 0;
341 ty->state.appcursor = 0;
342 ty->state.wrap = 1;
343 ty->state.wrapnext = 0;
344 ty->state.hidecursor = 0;
345 ty->state.crlf = 0;
346 ty->state.had_cr = 0;
347}
348
349void
350_termpty_cursor_copy(Termstate *state, Termstate *dest)
351{
352 dest->cx = state->cx;
353 dest->cy = state->cy;
354}
diff --git a/src/bin/termptyops.h b/src/bin/termptyops.h
new file mode 100644
index 0000000..bf93c6b
--- /dev/null
+++ b/src/bin/termptyops.h
@@ -0,0 +1,21 @@
1typedef enum _Termpty_Clear
2{
3 TERMPTY_CLR_END,
4 TERMPTY_CLR_BEGIN,
5 TERMPTY_CLR_ALL
6} Termpty_Clear;
7
8void _termpty_text_copy(Termpty *ty, Termcell *cells, Termcell *dest, int count);
9void _termpty_text_scroll(Termpty *ty);
10void _termpty_text_scroll_rev(Termpty *ty);
11void _termpty_text_scroll_test(Termpty *ty);
12void _termpty_text_scroll_rev_test(Termpty *ty);
13void _termpty_text_append(Termpty *ty, const Eina_Unicode *codepoints, int len);
14void _termpty_clear_line(Termpty *ty, Termpty_Clear mode, int limit);
15void _termpty_clear_screen(Termpty *ty, Termpty_Clear mode);
16void _termpty_clear_all(Termpty *ty);
17void _termpty_reset_att(Termatt *att);
18void _termpty_reset_state(Termpty *ty);
19void _termpty_cursor_copy(Termstate *state, Termstate *dest);
20
21#define _term_txt_write(ty, txt) termpty_write(ty, txt, sizeof(txt) - 1)