termio.c termio.h \
termpty.c termpty.h \
termptydbl.c termptydbl.h \
+termptyesc.c termptyesc.h \
+termptyops.c termptyops.h \
+termptygfx.c termptygfx.h \
+termptyext.c termptyext.h \
utf8.c utf8.h \
win.c win.h \
utils.c utils.h
#include "private.h"
-
#include <Elementary.h>
#include "termpty.h"
-#include "termptydbl.h"
+#include "termptyesc.h"
+#include "termptyops.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
/* specific log domain to help debug only terminal code parser */
-static int _termpty_log_dom = -1;
+int _termpty_log_dom = -1;
#undef CRITICAL
#undef ERR
}
static void
-_text_clear(Termpty *ty, Termcell *cells, int count, int val, Eina_Bool inherit_att)
-{
- int i;
- Termatt clear;
-
- memset(&clear, 0, sizeof(clear));
- if (inherit_att)
- {
- for (i = 0; i < count; i++)
- {
- cells[i].codepoint = val;
- cells[i].att = ty->state.att;
- }
- }
- else
- {
- for (i = 0; i < count; i++)
- {
- cells[i].codepoint = val;
- cells[i].att = clear;
- }
- }
-}
-
-static void
-_text_copy(Termpty *ty __UNUSED__, Termcell *cells, Termcell *dest, int count)
-{
- memcpy(dest, cells, sizeof(*(cells)) * count);
-}
-
-static void
-_text_save_top(Termpty *ty)
-{
- Termsave *ts;
-
- if (ty->backmax <= 0) return;
- ts = malloc(sizeof(Termsave) + ((ty->w - 1) * sizeof(Termcell)));
- ts->w = ty->w;
- _text_copy(ty, ty->screen, ts->cell, ty->w);
- if (!ty->back) ty->back = calloc(1, sizeof(Termsave *) * ty->backmax);
- if (ty->back[ty->backpos]) free(ty->back[ty->backpos]);
- ty->back[ty->backpos] = ts;
- ty->backpos++;
- if (ty->backpos >= ty->backmax) ty->backpos = 0;
- ty->backscroll_num++;
- if (ty->backscroll_num >= ty->backmax) ty->backscroll_num = ty->backmax - 1;
-}
-
-static void
-_text_scroll(Termpty *ty)
-{
- Termcell *cells = NULL, *cells2;
- int y, start_y = 0, end_y = ty->h - 1;
-
- if (ty->state.scroll_y2 != 0)
- {
- start_y = ty->state.scroll_y1;
- end_y = ty->state.scroll_y2 - 1;
- }
- else
- {
- if (!ty->altbuf)
- {
- _text_save_top(ty);
- if (ty->cb.scroll.func) ty->cb.scroll.func(ty->cb.scroll.data);
- }
- else
- if (ty->cb.cancel_sel.func)
- ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
- }
- DBG("... scroll!!!!! [%i->%i]", start_y, end_y);
- cells2 = &(ty->screen[end_y * ty->w]);
- for (y = start_y; y < end_y; y++)
- {
- cells = &(ty->screen[y * ty->w]);
- cells2 = &(ty->screen[(y + 1) * ty->w]);
- _text_copy(ty, cells2, cells, ty->w);
- }
- _text_clear(ty, cells2, ty->w, ' ', EINA_TRUE);
-}
-
-static void
-_text_scroll_rev(Termpty *ty)
-{
- Termcell *cells, *cells2 = NULL;
- int y, start_y = 0, end_y = ty->h - 1;
-
- if (ty->state.scroll_y2 != 0)
- {
- start_y = ty->state.scroll_y1;
- end_y = ty->state.scroll_y2 - 1;
- }
- DBG("... scroll rev!!!!! [%i->%i]", start_y, end_y);
- cells = &(ty->screen[end_y * ty->w]);
- for (y = end_y; y > start_y; y--)
- {
- cells = &(ty->screen[(y - 1) * ty->w]);
- cells2 = &(ty->screen[y * ty->w]);
- _text_copy(ty, cells, cells2, ty->w);
- }
- _text_clear(ty, cells, ty->w, ' ', EINA_TRUE);
-}
-
-static void
-_text_scroll_test(Termpty *ty)
-{
- int e = ty->h;
-
- if (ty->state.scroll_y2 != 0) e = ty->state.scroll_y2;
- if (ty->state.cy >= e)
- {
- _text_scroll(ty);
- ty->state.cy = e - 1;
- }
-}
-
-static void
-_text_scroll_rev_test(Termpty *ty)
-{
- int b = 0;
-
- if (ty->state.scroll_y2 != 0) b = ty->state.scroll_y1;
- if (ty->state.cy < b)
- {
- _text_scroll_rev(ty);
- ty->state.cy = b;
- }
-}
-
-/* translates VT100 ACS escape codes to Unicode values.
- * Based on rxvt-unicode screen.C table.
- */
-static const int vt100_to_unicode[62] =
-{
-// ? ? ? ? ? ? ?
-// A=UPARR B=DNARR C=RTARR D=LFARR E=FLBLK F=3/4BL G=SNOMN
- 0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603,
-// H= I= J= K= L= M= N=
- 0, 0, 0, 0, 0, 0, 0,
-// O= P= Q= R= S= T= U=
- 0, 0, 0, 0, 0, 0, 0,
-// V= W= X= Y= Z= [= \=
- 0, 0, 0, 0, 0, 0, 0,
-// ? ? v->0 v->1 v->2 v->3 v->4
-// ]= ^= _=SPC `=DIAMN a=HSMED b=HT c=FF
- 0, 0, 0x0020, 0x25c6, 0x2592, 0x2409, 0x240c,
-// v->5 v->6 v->7 v->8 v->9 v->a v->b
-// d=CR e=LF f=DEGRE g=PLSMN h=NL i=VT j=SL-BR
- 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518,
-// v->c v->d v->e v->f v->10 v->11 v->12
-// k=SL-TR l=SL-TL m=SL-BL n=SL-+ o=SL-T1 p=SL-T2 q=SL-HZ
- 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, 0x23bb, 0x2500,
-// v->13 v->14 v->15 v->16 v->17 v->18 v->19
-// r=SL-T4 s=SL-T5 t=SL-VR u=SL-VL v=SL-HU w=Sl-HD x=SL-VT
- 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502,
-// v->1a v->1b b->1c v->1d v->1e/a3 v->1f
-// y=LT-EQ z=GT-EQ {=PI |=NOTEQ }=POUND ~=DOT
- 0x2264, 0x2265, 0x03c0, 0x2260, 0x20a4, 0x00b7
-};
-
-static void
-_text_append(Termpty *ty, const int *codepoints, int len)
-{
- Termcell *cells;
- int i, j;
-
- cells = &(ty->screen[ty->state.cy * ty->w]);
- for (i = 0; i < len; i++)
- {
- int g;
-
- if (ty->state.wrapnext)
- {
- cells[ty->state.cx].att.autowrapped = 1;
- ty->state.wrapnext = 0;
- ty->state.cx = 0;
- ty->state.cy++;
- _text_scroll_test(ty);
- cells = &(ty->screen[ty->state.cy * ty->w]);
- }
- if (ty->state.insert)
- {
- for (j = ty->w - 1; j > ty->state.cx; j--)
- cells[j] = cells[j - 1];
- }
-
- g = codepoints[i];
- switch (ty->state.charsetch)
- {
- case '0': /* DEC Special Character & Line Drawing Set */
- if ((g >= 0x41) && (g <= 0x7e) &&
- (vt100_to_unicode[g - 0x41]))
- g = vt100_to_unicode[g - 0x41];
- break;
- case 'A': /* UK, replaces # with GBP */
- if (g == '#') g = 0x20a4;
- break;
- default:
- break;
- }
-
- cells[ty->state.cx].codepoint = g;
- cells[ty->state.cx].att = ty->state.att;
-#if defined(SUPPORT_DBLWIDTH)
- cells[ty->state.cx].att.dblwidth = _termpty_is_dblwidth_get(ty, g);
- if ((cells[ty->state.cx].att.dblwidth) && (ty->state.cx < (ty->w - 1)))
- {
- cells[ty->state.cx + 1].codepoint = 0;
- cells[ty->state.cx + 1].att = cells[ty->state.cx].att;
- }
-#endif
- if (ty->state.wrap)
- {
- ty->state.wrapnext = 0;
-#if defined(SUPPORT_DBLWIDTH)
- if (cells[ty->state.cx].att.dblwidth)
- {
- if (ty->state.cx >= (ty->w - 2)) ty->state.wrapnext = 1;
- else ty->state.cx += 2;
- }
- else
- {
- if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
- else ty->state.cx++;
- }
-#else
- if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
- else ty->state.cx++;
-#endif
- }
- else
- {
- ty->state.wrapnext = 0;
- ty->state.cx++;
-#if defined(SUPPORT_DBLWIDTH)
- if (cells[ty->state.cx].att.dblwidth)
- {
- ty->state.cx++;
- if (ty->state.cx >= (ty->w - 1))
- ty->state.cx = ty->w - 2;
- }
- else
- {
- if (ty->state.cx >= ty->w)
- ty->state.cx = ty->w - 1;
- }
-#else
- if (ty->state.cx >= ty->w)
- ty->state.cx = ty->w - 1;
-#endif
- }
- }
-}
-
-static void
-_term_write(Termpty *ty, const char *txt, int size)
-{
- if (write(ty->fd, txt, size) < 0) ERR("write: %s", strerror(errno));
-}
-#define _term_txt_write(ty, txt) _term_write(ty, txt, sizeof(txt) - 1)
-
-#define CLR_END 0
-#define CLR_BEGIN 1
-#define CLR_ALL 2
-
-static void
-_clear_line(Termpty *ty, int mode, int limit)
-{
- Termcell *cells;
- int n = 0;
-
- cells = &(ty->screen[ty->state.cy * ty->w]);
- switch (mode)
- {
- case CLR_END:
- n = ty->w - ty->state.cx;
- cells = &(cells[ty->state.cx]);
- break;
- case CLR_BEGIN:
- n = ty->state.cx + 1;
- break;
- case CLR_ALL:
- n = ty->w;
- break;
- default:
- return;
- }
- if (n > limit) n = limit;
- _text_clear(ty, cells, n, 0, EINA_TRUE);
-}
-
-static void
-_clear_screen(Termpty *ty, int mode)
-{
- Termcell *cells;
-
- cells = ty->screen;
- switch (mode)
- {
- case CLR_END:
- _clear_line(ty, mode, ty->w);
- if (ty->state.cy < (ty->h - 1))
- {
- cells = &(ty->screen[(ty->state.cy + 1) * ty->w]);
- _text_clear(ty, cells, ty->w * (ty->h - ty->state.cy - 1), 0, EINA_TRUE);
- }
- break;
- case CLR_BEGIN:
- if (ty->state.cy > 0)
- _text_clear(ty, cells, ty->w * ty->state.cy, 0, EINA_TRUE);
- _clear_line(ty, mode, ty->w);
- break;
- case CLR_ALL:
- _text_clear(ty, cells, ty->w * ty->h, 0, EINA_TRUE);
- break;
- default:
- break;
- }
- if (ty->cb.cancel_sel.func)
- ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
-}
-
-static void
-_clear_all(Termpty *ty)
-{
- if (!ty->screen) return;
- memset(ty->screen, 0, sizeof(*(ty->screen)) * ty->w * ty->h);
-}
-
-static void
-_reset_att(Termatt *att)
-{
- att->fg = COL_DEF;
- att->bg = COL_DEF;
- att->bold = 0;
- att->faint = 0;
-#if defined(SUPPORT_ITALIC)
- att->italic = 0;
-#elif defined(SUPPORT_DBLWIDTH)
- att->dblwidth = 0;
-#endif
- att->underline = 0;
- att->blink = 0;
- att->blink2 = 0;
- att->inverse = 0;
- att->invisible = 0;
- att->strike = 0;
- att->fg256 = 0;
- att->bg256 = 0;
- att->fgintense = 0;
- att->bgintense = 0;
- att->autowrapped = 0;
- att->newline = 0;
- att->tab = 0;
-}
-
-static void
-_reset_state(Termpty *ty)
-{
- ty->state.cx = 0;
- ty->state.cy = 0;
- ty->state.scroll_y1 = 0;
- ty->state.scroll_y2 = 0;
- ty->state.had_cr_x = 0;
- ty->state.had_cr_y = 0;
- _reset_att(&(ty->state.att));
- ty->state.charset = 0;
- ty->state.charsetch = 'B';
- ty->state.chset[0] = 'B';
- ty->state.chset[1] = 'B';
- ty->state.chset[2] = 'B';
- ty->state.chset[3] = 'B';
- ty->state.multibyte = 0;
- ty->state.alt_kp = 0;
- ty->state.insert = 0;
- ty->state.appcursor = 0;
- ty->state.wrap = 1;
- ty->state.wrapnext = 0;
- ty->state.hidecursor = 0;
- ty->state.crlf = 0;
- ty->state.had_cr = 0;
-}
-
-static void
-_cursor_copy(Termstate *state, Termstate *dest)
-{
- dest->cx = state->cx;
- dest->cy = state->cy;
-}
-
-static int
-_csi_arg_get(Eina_Unicode **ptr)
-{
- Eina_Unicode *b = *ptr;
- int octal = 0;
- int sum = 0;
-
- while ((*b) && (!isdigit(*b))) b++;
- if (!*b)
- {
- *ptr = NULL;
- return 0;
- }
- if (*b == '0') octal = 1;
- while (isdigit(*b))
- {
- if (octal) sum *= 8;
- else sum *= 10;
- sum += *b - '0';
- b++;
- }
- *ptr = b;
- return sum;
-}
-
-static int
-_handle_esc_csi(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
-{
- Eina_Unicode *cc;
- int arg, first = 1, i;
- Eina_Unicode buf[4096], *b;
-
- cc = (Eina_Unicode *)c;
- b = buf;
- while ((cc < ce) && (*cc >= '0') && (*cc <= '?'))
- {
- *b = *cc;
- b++;
- cc++;
- }
- // if cc == ce then we got to the end of the string with no end marker
- // so return -2 to indicate to go back to the escape beginning when
- // there is more bufer available
- if (cc == ce) return -2;
- *b = 0;
- b = buf;
-// DBG(" CSI: '%c' args '%s'", *cc, buf);
- switch (*cc)
- {
- case 'm': // color set
- while (b)
- {
- arg = _csi_arg_get(&b);
- if ((first) && (!b))
- _reset_att(&(ty->state.att));
- else if (b)
- {
- first = 0;
- switch (arg)
- {
- case 0: // reset to normal
- _reset_att(&(ty->state.att));
- break;
- case 1: // bold/bright
- ty->state.att.bold = 1;
- break;
- case 2: // faint
- ty->state.att.faint = 1;
- break;
- case 3: // italic
-#if defined(SUPPORT_ITALIC)
- ty->state.att.italic = 1;
-#endif
- break;
- case 4: // underline
- ty->state.att.underline = 1;
- break;
- case 5: // blink
- ty->state.att.blink = 1;
- break;
- case 6: // blink rapid
- ty->state.att.blink2 = 1;
- break;
- case 7: // reverse
- ty->state.att.inverse = 1;
- break;
- case 8: // invisible
- ty->state.att.invisible = 1;
- break;
- case 9: // strikethrough
- ty->state.att.strike = 1;
- break;
- case 21: // no bold/bright
- ty->state.att.bold = 0;
- break;
- case 22: // no faint
- ty->state.att.faint = 0;
- break;
- case 23: // no italic
-#if defined(SUPPORT_ITALIC)
- ty->state.att.italic = 0;
-#endif
- break;
- case 24: // no underline
- ty->state.att.underline = 0;
- break;
- case 25: // no blink
- ty->state.att.blink = 0;
- ty->state.att.blink2 = 0;
- break;
- case 27: // no reverse
- ty->state.att.inverse = 0;
- break;
- case 28: // no invisible
- ty->state.att.invisible = 0;
- break;
- case 29: // no strikethrough
- ty->state.att.strike = 0;
- break;
- case 30: // fg
- case 31:
- case 32:
- case 33:
- case 34:
- case 35:
- case 36:
- case 37:
- ty->state.att.fg256 = 0;
- ty->state.att.fg = (arg - 30) + COL_BLACK;
- ty->state.att.fgintense = 0;
- break;
- case 38: // xterm 256 fg color ???
- // now check if next arg is 5
- arg = _csi_arg_get(&b);
- if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
- else
- {
- // then get next arg - should be color index 0-255
- arg = _csi_arg_get(&b);
- if (!b) ERR("Failed xterm 256 color fg esc val");
- else
- {
- ty->state.att.fg256 = 1;
- ty->state.att.fg = arg;
- }
- }
- ty->state.att.fgintense = 0;
- break;
- case 39: // default fg color
- ty->state.att.fg256 = 0;
- ty->state.att.fg = COL_DEF;
- ty->state.att.fgintense = 0;
- break;
- case 40: // bg
- case 41:
- case 42:
- case 43:
- case 44:
- case 45:
- case 46:
- case 47:
- ty->state.att.bg256 = 0;
- ty->state.att.bg = (arg - 40) + COL_BLACK;
- ty->state.att.bgintense = 0;
- break;
- case 48: // xterm 256 bg color ???
- // now check if next arg is 5
- arg = _csi_arg_get(&b);
- if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
- else
- {
- // then get next arg - should be color index 0-255
- arg = _csi_arg_get(&b);
- if (!b) ERR("Failed xterm 256 color bg esc val");
- else
- {
- ty->state.att.bg256 = 1;
- ty->state.att.bg = arg;
- }
- }
- ty->state.att.bgintense = 0;
- break;
- case 49: // default bg color
- ty->state.att.bg256 = 0;
- ty->state.att.bg = COL_DEF;
- ty->state.att.bgintense = 0;
- break;
- case 90: // fg
- case 91:
- case 92:
- case 93:
- case 94:
- case 95:
- case 96:
- case 97:
- ty->state.att.fg256 = 0;
- ty->state.att.fg = (arg - 90) + COL_BLACK;
- ty->state.att.fgintense = 1;
- break;
- case 98: // xterm 256 fg color ???
- // now check if next arg is 5
- arg = _csi_arg_get(&b);
- if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
- else
- {
- // then get next arg - should be color index 0-255
- arg = _csi_arg_get(&b);
- if (!b) ERR("Failed xterm 256 color fg esc val");
- else
- {
- ty->state.att.fg256 = 1;
- ty->state.att.fg = arg;
- }
- }
- ty->state.att.fgintense = 1;
- break;
- case 99: // default fg color
- ty->state.att.fg256 = 0;
- ty->state.att.fg = COL_DEF;
- ty->state.att.fgintense = 1;
- break;
- case 100: // bg
- case 101:
- case 102:
- case 103:
- case 104:
- case 105:
- case 106:
- case 107:
- ty->state.att.bg256 = 0;
- ty->state.att.bg = (arg - 100) + COL_BLACK;
- ty->state.att.bgintense = 1;
- break;
- case 108: // xterm 256 bg color ???
- // now check if next arg is 5
- arg = _csi_arg_get(&b);
- if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
- else
- {
- // then get next arg - should be color index 0-255
- arg = _csi_arg_get(&b);
- if (!b) ERR("Failed xterm 256 color bg esc val");
- else
- {
- ty->state.att.bg256 = 1;
- ty->state.att.bg = arg;
- }
- }
- ty->state.att.bgintense = 1;
- break;
- case 109: // default bg color
- ty->state.att.bg256 = 0;
- ty->state.att.bg = COL_DEF;
- ty->state.att.bgintense = 1;
- break;
- default: // not handled???
- ERR(" color cmd [%i] not handled", arg);
- break;
- }
- }
- }
- break;
- case '@': // insert N blank chars
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- {
- int pi = ty->state.insert;
- int blank[1] = { ' ' };
- int cx = ty->state.cx;
-
- ty->state.wrapnext = 0;
- ty->state.insert = 1;
- for (i = 0; i < arg; i++)
- _text_append(ty, blank, 1);
- ty->state.insert = pi;
- ty->state.cx = cx;
- }
- break;
- case 'A': // cursor up N
- case 'e': // cursor up N
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- for (i = 0; i < arg; i++)
- {
- ty->state.cy--;
- _text_scroll_rev_test(ty);
- }
- break;
- case 'B': // cursor down N
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- for (i = 0; i < arg; i++)
- {
- ty->state.cy++;
- _text_scroll_test(ty);
- }
- break;
- case 'D': // cursor left N
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- for (i = 0; i < arg; i++)
- {
- ty->state.cx--;
- if (ty->state.cx < 0) ty->state.cx = 0;
- }
- break;
- case 'C': // cursor right N
- case 'a': // cursor right N
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- for (i = 0; i < arg; i++)
- {
- ty->state.cx++;
- if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
- }
- break;
- case 'H': // cursor pos set
- case 'f': // cursor pos set
- ty->state.wrapnext = 0;
- if (!*b)
- {
- ty->state.cx = 0;
- ty->state.cy = 0;
- }
- else
- {
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- arg--;
- if (arg < 0) arg = 0;
- else if (arg >= ty->h) arg = ty->h - 1;
- if (b) ty->state.cy = arg;
- if (b)
- {
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- arg--;
- }
- else arg = 0;
- if (arg < 0) arg = 0;
- else if (arg >= ty->w) arg = ty->w - 1;
- if (b) ty->state.cx = arg;
- }
- break;
- case 'G': // to column N
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- ty->state.cx = arg - 1;
- if (ty->state.cx < 0) ty->state.cx = 0;
- else if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
- break;
- case 'd': // to row N
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- ty->state.cy = arg - 1;
- if (ty->state.cy < 0) ty->state.cy = 0;
- else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
- break;
- case 'E': // down relative N rows, and to col 0
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- ty->state.cy += arg;
- if (ty->state.cy < 0) ty->state.cy = 0;
- else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
- ty->state.cx = 0;
- break;
- case 'F': // up relative N rows, and to col 0
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- ty->state.wrapnext = 0;
- ty->state.cy -= arg;
- if (ty->state.cy < 0) ty->state.cy = 0;
- else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
- ty->state.cx = 0;
- break;
- case 'X': // erase N chars
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- _clear_line(ty, CLR_END, arg);
- break;
- case 'S': // scroll up N lines
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- for (i = 0; i < arg; i++) _text_scroll(ty);
- break;
- case 'T': // scroll down N lines
- arg = _csi_arg_get(&b);
- if (arg < 1) arg = 1;
- for (i = 0; i < arg; i++) _text_scroll_rev(ty);
- break;
- case 'M': // delete N lines - cy
- case 'L': // insert N lines - cy
- arg = _csi_arg_get(&b);
- {
- int sy1, sy2;
-
- sy1 = ty->state.scroll_y1;
- sy2 = ty->state.scroll_y2;
- if (ty->state.scroll_y2 == 0)
- {
- ty->state.scroll_y1 = ty->state.cy;
- ty->state.scroll_y2 = ty->h;
- }
- else
- {
- ty->state.scroll_y1 = ty->state.cy;
- if (ty->state.scroll_y2 <= ty->state.scroll_y1)
- ty->state.scroll_y2 = ty->state.scroll_y1 + 1;
- }
- if (arg < 1) arg = 1;
- for (i = 0; i < arg; i++)
- {
- if (*cc == 'M') _text_scroll(ty);
- else _text_scroll_rev(ty);
- }
- ty->state.scroll_y1 = sy1;
- ty->state.scroll_y2 = sy2;
- }
- break;
- case 'P': // erase and scrollback N chars
- arg = _csi_arg_get(&b);
- {
- Termcell *cells;
- int x, lim;
-
- if (arg < 1) arg = 1;
- cells = &(ty->screen[ty->state.cy * ty->w]);
- lim = ty->w - arg;
- for (x = ty->state.cx; x < (ty->w); x++)
- {
- if (x < lim)
- cells[x] = cells[x + arg];
- else
- memset(&(cells[x]), 0, sizeof(*cells));
- }
- }
- break;
- case 'c': // query device id
- {
- char bf[32];
-// 0 Base VT100, no options
-// 1 Preprocessor option (STP)
-// 2 Advanced video option (AVO)
-// 3 AVO and STP
-// 4 Graphics processor option (GO)
-// 5 GO and STP
-// 6 GO and AVO
-// 7 GO, STP, and AVO
- snprintf(bf, sizeof(bf), "\033[?1;%ic", 0);
- _term_write(ty, bf, strlen(bf));
- }
- break;
- case 'J': // "2j" erases the screen, 1j erase from screen start to curs, 0j erase cursor to end of screen
- arg = _csi_arg_get(&b);
- if (b)
- {
- if ((arg >= CLR_END) && (arg <= CLR_ALL))
- _clear_screen(ty, arg);
- else
- ERR("invalid clr scr %i", arg);
- }
- else _clear_screen(ty, CLR_END);
- break;
- case 'K': // 0K erase to end of line, 1K erase from screen start to cursor, 2K erase all of line
- arg = _csi_arg_get(&b);
- if (b)
- {
- if ((arg >= CLR_END) && (arg <= CLR_ALL))
- _clear_line(ty, arg, ty->w);
- else
- ERR("invalid clr lin %i", arg);
- }
- else _clear_line(ty, CLR_END, ty->w);
- break;
- case 'h': // list - set screen mode or line wrap ("7h" == turn on line wrap, "7l" disables line wrap , ...)
- case 'l':
- {
- int mode = 0, priv = 0;
- int handled = 0;
-
- if (*cc == 'h') mode = 1;
- if (*b == '?')
- {
- priv = 1;
- b++;
- }
- if (priv)
- {
- while (b)
- {
- arg = _csi_arg_get(&b);
- if (b)
- {
- int size;
-
- // complete-ish list here:
- // http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html
- switch (arg)
- {
- case 1:
- handled = 1;
- ty->state.appcursor = mode;
- break;
- case 2:
- handled = 1;
- ty->state.kbd_lock = mode;
- break;
- case 3: // should we handle this?
- handled = 1;
- ERR("XXX: 132 column mode %i", mode);
- break;
- case 4:
- handled = 1;
- ERR("XXX: set insert mode to %i", mode);
- break;
- case 5:
- handled = 1;
- ty->state.reverse = mode;
- break;
- case 6:
- handled = 1;
- ERR("XXX: origin mode: cursor is at 0,0/cursor limited to screen/start point for line #'s depends on top margin");
- break;
- case 7:
- handled = 1;
- DBG("DDD: set wrap mode to %i", mode);
- ty->state.wrap = mode;
- break;
- case 8:
- handled = 1;
- ty->state.no_autorepeat = !mode;
- INF("XXX: auto repeat %i", mode);
- break;
- case 9:
- handled = 1;
- if (mode) ty->mouse_rep = MOUSE_X10;
- else ty->mouse_rep = MOUSE_OFF;
- break;
- case 12: // ignore
- handled = 1;
-// DBG("XXX: set blinking cursor to (stop?) %i or local echo", mode);
- break;
- case 19: // never seen this - what to do?
- handled = 1;
-// INF("XXX: set print extent to full screen");
- break;
- case 20: // crfl==1 -> cur moves to col 0 on LF, FF or VT, ==0 -> mode is cr+lf
- handled = 1;
- ty->state.crlf = mode;
- break;
- case 25:
- handled = 1;
- ty->state.hidecursor = !mode;
- break;
- case 30: // ignore
- handled = 1;
-// DBG("XXX: set scrollbar mapping %i", mode);
- break;
- case 33: // ignore
- handled = 1;
-// INF("XXX: Stop cursor blink %i", mode);
- break;
- case 34: // ignore
- handled = 1;
-// INF("XXX: Underline cursor mode %i", mode);
- break;
- case 35: // ignore
- handled = 1;
-// DBG("XXX: set shift keys %i", mode);
- break;
- case 38: // ignore
- handled = 1;
-// INF("XXX: switch to tek window %i", mode);
- break;
- case 59: // ignore
- handled = 1;
-// INF("XXX: kanji terminal mode %i", mode);
- break;
- case 66:
- handled = 1;
- ERR("XXX: app keypad mode %i", mode);
- break;
- case 67:
- handled = 1;
- ty->state.send_bs = mode;
- INF("XXX: backspace send bs not del = %i", mode);
- break;
- case 1000:
- handled = 1;
- if (mode) ty->mouse_rep = MOUSE_NORMAL;
- else ty->mouse_rep = MOUSE_OFF;
- INF("XXX: set mouse (press+release only) to %i", mode);
- break;
- case 1001:
- handled = 1;
- ERR("XXX: x11 mouse highlighting %i", mode);
- break;
- case 1002:
- handled = 1;
- ERR("XXX: set mouse (press+relese+motion while pressed) %i", mode);
- break;
- case 1003:
- handled = 1;
- ERR("XXX: set mouse (press+relese+all motion) %i", mode);
- break;
- case 1004: // i dont know what focus repporting is?
- handled = 1;
- ERR("XXX: enable focus reporting %i", mode);
- break;
- case 1005:
- handled = 1;
- if (mode) ty->mouse_rep = MOUSE_UTF8;
- else ty->mouse_rep = MOUSE_OFF;
- INF("XXX: set mouse (xterm utf8 style) %i", mode);
- break;
- case 1006:
- handled = 1;
- if (mode) ty->mouse_rep = MOUSE_SGR;
- else ty->mouse_rep = MOUSE_OFF;
- INF("XXX: set mouse (xterm sgr style) %i", mode);
- break;
- case 1010: // ignore
- handled = 1;
-// DBG("XXX: set home on tty output %i", mode);
- break;
- case 1012: // ignore
- handled = 1;
-// DBG("XXX: set home on tty input %i", mode);
- break;
- case 1015:
- handled = 1;
- if (mode) ty->mouse_rep = MOUSE_URXVT;
- else ty->mouse_rep = MOUSE_OFF;
- INF("XXX: set mouse (rxvt-unicdode style) %i", mode);
- break;
- case 1034: // ignore
- /* libreadline6 emits it but it shouldn't.
- See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=577012
- */
- handled = 1;
-// DBG("Ignored screen mode %i", arg);
- break;
- case 1047:
- case 1049:
- case 47:
- handled = 1;
- DBG("DDD: switch buf");
- if (ty->altbuf)
- {
- // if we are looking at alt buf now,
- // clear main buf before we swap it back
- // into the sreen2 save (so save is
- // clear)
- _clear_all(ty);
-// _cursor_copy(&(ty->swap), &(ty->state));
- ty->state = ty->swap;
- }
- else
- {
-// _cursor_copy(&(ty->state), &(ty->swap));
- ty->swap = ty->state;
- }
- size = ty->w * ty->h;
- // swap screen content now
- for (i = 0; i < size; i++)
- {
- Termcell t;
-
- t = ty->screen[i];
- ty->screen[i] = ty->screen2[i];
- ty->screen2[i] = t;
- }
- ty->altbuf = !ty->altbuf;
- if (ty->cb.cancel_sel.func)
- ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
- break;
- case 1048:
- if (mode)
- _cursor_copy(&(ty->state), &(ty->save));
- else
- _cursor_copy(&(ty->save), &(ty->state));
- break;
- case 2004: // ignore
- handled = 1;
-// INF("XXX: enable bracketed paste mode %i", mode);
- break;
- case 7727: // ignore
- handled = 1;
-// INF("XXX: enable application escape mode %i", mode);
- break;
- case 7786: // ignore
- handled = 1;
-// INF("XXX: enable mouse wheel -> cursor key xlation %i", mode);
- break;
- default:
- ERR("unhandled screen mode arg %i", arg);
- break;
- }
- }
- }
- }
- else
- {
- while (b)
- {
- arg = _csi_arg_get(&b);
- if (b)
- {
- if (arg == 1)
- {
- handled = 1;
- ty->state.appcursor = mode;
- }
- else if (arg == 4)
- {
- handled = 1;
- DBG("DDD: set insert mode to %i", mode);
- ty->state.insert = mode;
- }
-// else if (arg == 24)
-// {
-// ERR("unhandled #24 arg %i", arg);
-// // ???
-// }
- else
- ERR("unhandled screen non-priv mode arg %i, mode %i, ch '%c'", arg, mode, *cc);
- }
- }
- }
- if (!handled) ERR("unhandled '%c'", *cc);
- }
- break;
- case 'r':
- arg = _csi_arg_get(&b);
- if (!b)
- {
- INF("no region args reset region");
- ty->state.scroll_y1 = 0;
- ty->state.scroll_y2 = 0;
- }
- else
- {
- int arg2;
-
- arg2 = _csi_arg_get(&b);
- if (!b)
- {
- INF("failed to give 2 region args reset region");
- ty->state.scroll_y1 = 0;
- ty->state.scroll_y2 = 0;
- }
- else
- {
- if (arg > arg2)
- {
- ERR("scroll region beginning > end [%i %i]", arg, arg2);
- ty->state.scroll_y1 = 0;
- ty->state.scroll_y2 = 0;
- }
- else
- {
- INF("2 region args: %i %i", arg, arg2);
- if (arg >= ty->h) arg = ty->h - 1;
- if (arg2 > ty->h) arg2 = ty->h;
- arg2++;
- ty->state.scroll_y1 = arg - 1;
- ty->state.scroll_y2 = arg2 - 1;
- }
- }
- }
- break;
- case 's': // store cursor pos
- _cursor_copy(&(ty->state), &(ty->save));
- break;
- case 'u': // restore cursor pos
- _cursor_copy(&(ty->save), &(ty->state));
- break;
-/*
- case 'R': // report cursor
- break;
- case 'n': // "6n" queires cursor pos, 0n, 3n, 5n too
- break;
- case 's':
- break;
- case 't':
- break;
- case 'p': // define key assignments based on keycode
- break;
- case 'q': // set/clear led's
- break;
- case 'x': // request terminal parameters
- break;
- case 'r': // set top and bottom margins
- break;
- case 'y': // invoke confidence test
- break;
- case 'g': // clear tabulation
- break;
- */
- default:
- ERR("unhandled CSI '%c' (0x%02x)", *cc, *cc);
- break;
- }
- cc++;
- return cc - c;
-}
-
-static int
-_handle_esc_xterm(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
-{
- Eina_Unicode *cc;
- Eina_Unicode buf[4096], *b;
- char *s;
- int len = 0;
-
- cc = (Eina_Unicode *)c;
- b = buf;
- while ((cc < ce) && (*cc >= ' ') && (*cc < 0x7f))
- {
- *b = *cc;
- b++;
- cc++;
- }
- *b = 0;
- if ((*cc < ' ') || (*cc >= 0x7f)) cc++;
- else return -2;
- switch (buf[0])
- {
- case '0':
- // XXX: title + name - callback
- s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
- if (ty->prop.title) eina_stringshare_del(ty->prop.title);
- if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
- if (b)
- {
- ty->prop.title = eina_stringshare_add(s);
- ty->prop.icon = eina_stringshare_add(s);
- free(s);
- }
- else
- {
- ty->prop.title = NULL;
- ty->prop.icon = NULL;
- }
- if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
- if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
- break;
- case '1':
- // XXX: icon name - callback
- s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
- if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
- if (s)
- {
- ty->prop.icon = eina_stringshare_add(s);
- free(s);
- }
- else
- {
- ty->prop.icon = NULL;
- }
- if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
- break;
- case '2':
- // XXX: title - callback
- s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
- if (ty->prop.title) eina_stringshare_del(ty->prop.title);
- if (s)
- {
- ty->prop.title = eina_stringshare_add(s);
- free(s);
- }
- else
- {
- ty->prop.title = NULL;
- }
- if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
- break;
- case '4':
- // XXX: set palette entry. not supported.
- b = &(buf[2]);
- break;
- default:
- // many others
- ERR("unhandled xterm esc '%c'", buf[0]);
- break;
- }
- return cc - c;
-}
-
-static int
-_handle_esc_terminology(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
-{
- Eina_Unicode *cc;
- Eina_Unicode buf[4096], *b;
- char *s;
- int slen = 0;
-
- cc = (Eina_Unicode *)c;
- b = buf;
- while ((cc < ce) && (*cc != 0x0))
- {
- *b = *cc;
- b++;
- cc++;
- }
- *b = 0;
- if (*cc == 0x0) cc++;
- else return -2;
- // commands are stored in the buffer, 0 bytes not allowd (end marker)
- s = eina_unicode_unicode_to_utf8(buf, &slen);
- ty->cur_cmd = s;
- if (ty->cb.command.func) ty->cb.command.func(ty->cb.command.data);
- ty->cur_cmd = NULL;
- if (s) free(s);
- return cc - c;
-}
-
-static int
-_handle_esc(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
-{
- if ((ce - c) < 2) return 0;
- DBG("ESC: '%c'", c[1]);
- switch (c[1])
- {
- case '[':
- return 2 + _handle_esc_csi(ty, c + 2, ce);
- case ']':
- return 2 + _handle_esc_xterm(ty, c + 2, ce);
- case '}':
- return 2 + _handle_esc_terminology(ty, c + 2, ce);
- case '=': // set alternate keypad mode
- ty->state.alt_kp = 1;
- return 2;
- case '>': // set numeric keypad mode
- ty->state.alt_kp = 0;
- return 2;
- case 'M': // move to prev line
- ty->state.wrapnext = 0;
- ty->state.cy--;
- _text_scroll_rev_test(ty);
- return 2;
- case 'D': // move to next line
- ty->state.wrapnext = 0;
- ty->state.cy++;
- _text_scroll_test(ty);
- return 2;
- case 'E': // add \n\r
- ty->state.wrapnext = 0;
- ty->state.cx = 0;
- ty->state.cy++;
- _text_scroll_test(ty);
- return 2;
- case 'Z': // same a 'ESC [ Pn c'
- _term_txt_write(ty, "\033[?1;2C");
- return 2;
- case 'c': // reset terminal to initial state
- DBG("reset to init mode and clear");
- _reset_state(ty);
- _clear_screen(ty, CLR_ALL);
- if (ty->cb.cancel_sel.func)
- ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
- return 2;
- case '(': // charset 0
- ty->state.chset[0] = c[2];
- ty->state.multibyte = 0;
- ty->state.charsetch = c[2];
- return 3;
- case ')': // charset 1
- ty->state.chset[1] = c[2];
- ty->state.multibyte = 0;
- return 3;
- case '*': // charset 2
- ty->state.chset[2] = c[2];
- ty->state.multibyte = 0;
- return 3;
- case '+': // charset 3
- ty->state.chset[3] = c[2];
- ty->state.multibyte = 0;
- return 3;
- case '$': // charset -2
- ty->state.chset[2] = c[2];
- ty->state.multibyte = 1;
- return 3;
- case '#': // #8 == test mode -> fill screen with "E";
- if (c[2] == '8')
- {
- int i, size;
- Termcell *cells;
-
- DBG("reset to init mode and clear then fill with E");
- _reset_state(ty);
- ty->save = ty->state;
- ty->swap = ty->state;
- _clear_screen(ty, CLR_ALL);
- if (ty->cb.cancel_sel.func)
- ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
- cells = ty->screen;
- size = ty->w * ty->h;
- if (cells)
- {
- for (i = 0; i < size; i++) cells[i].codepoint = 'E';
- }
- }
- return 3;
- case '@': // just consume this plus next char
- return 3;
- case '7': // save cursor pos
- _cursor_copy(&(ty->state), &(ty->save));
- return 2;
- case '8': // restore cursor pos
- _cursor_copy(&(ty->save), &(ty->state));
- return 2;
-/*
- case 'G': // query gfx mode
- return 3;
- case 'H': // set tab at current column
- return 2;
- case 'n': // single shift 2
- return 2;
- case 'o': // single shift 3
- return 2;
- */
- default:
- ERR("eek - esc unhandled '%c' (0x%02x)", c[1], c[1]);
- break;
- }
- return 1;
-}
-
-static int
-_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce)
-{
- Eina_Unicode *cc;
- int len = 0;
-
-/*
- printf(" B: ");
- int j;
- for (j = 0; c + j < ce && j < 100; j++)
- {
- if ((c[j] < ' ') || (c[j] >= 0x7f))
- printf("\033[35m%02x\033[0m", c[j]);
- else
- printf("%c", c[j]);
- }
- printf("\n");
- */
- if (c[0] < 0x20)
- {
- switch (c[0])
- {
-/*
- case 0x00: // NUL
- return 1;
- case 0x01: // SOH (start of heading)
- return 1;
- case 0x02: // STX (start of text)
- return 1;
- case 0x03: // ETX (end of text)
- return 1;
- case 0x04: // EOT (end of transmission)
- return 1;
- */
- case 0x05: // ENQ (enquiry)
- _term_txt_write(ty, "ABC\r\n");
- ty->state.had_cr = 0;
- return 1;
-/*
- case 0x06: // ACK (acknowledge)
- return 1;
- */
- case 0x07: // BEL '\a' (bell)
- if (ty->cb.bell.func) ty->cb.bell.func(ty->cb.bell.data);
- ty->state.had_cr = 0;
- return 1;
- case 0x08: // BS '\b' (backspace)
- DBG("->BS");
- ty->state.wrapnext = 0;
- ty->state.cx--;
- if (ty->state.cx < 0) ty->state.cx = 0;
- ty->state.had_cr = 0;
- return 1;
- case 0x09: // HT '\t' (horizontal tab)
- DBG("->HT");
- ty->screen[ty->state.cx + (ty->state.cy * ty->w)].att.tab = 1;
- ty->state.wrapnext = 0;
- ty->state.cx += 8;
- ty->state.cx = (ty->state.cx / 8) * 8;
- if (ty->state.cx >= ty->w)
- ty->state.cx = ty->w - 1;
- ty->state.had_cr = 0;
- return 1;
- case 0x0a: // LF '\n' (new line)
- case 0x0b: // VT '\v' (vertical tab)
- case 0x0c: // FF '\f' (form feed)
- DBG("->LF");
- if (ty->state.had_cr)
- ty->screen[ty->state.had_cr_x + (ty->state.had_cr_y * ty->w)].att.newline = 1;
- ty->state.wrapnext = 0;
- if (ty->state.crlf) ty->state.cx = 0;
- ty->state.cy++;
- _text_scroll_test(ty);
- ty->state.had_cr = 0;
- return 1;
- case 0x0d: // CR '\r' (carriage ret)
- DBG("->CR");
- if (ty->state.cx != 0)
- {
- ty->state.had_cr_x = ty->state.cx;
- ty->state.had_cr_y = ty->state.cy;
- }
- ty->state.wrapnext = 0;
- ty->state.cx = 0;
- ty->state.had_cr = 1;
- return 1;
-
- case 0x0e: // SO (shift out) // Maps G1 character set into GL.
- ty->state.charset = 1;
- ty->state.charsetch = ty->state.chset[1];
- return 1;
- case 0x0f: // SI (shift in) // Maps G0 character set into GL.
- ty->state.charset = 0;
- ty->state.charsetch = ty->state.chset[0];
- return 1;
-/*
- case 0x10: // DLE (data link escape)
- return 1;
- case 0x11: // DC1 (device control 1)
- return 1;
- case 0x12: // DC2 (device control 2)
- return 1;
- case 0x13: // DC3 (device control 3)
- return 1;
- case 0x14: // DC4 (device control 4)
- return 1;
- case 0x15: // NAK (negative ack.)
- return 1;
- case 0x16: // SYN (synchronous idle)
- return 1;
- case 0x17: // ETB (end of trans. blk)
- return 1;
- case 0x18: // CAN (cancel)
- return 1;
- case 0x19: // EM (end of medium)
- return 1;
- case 0x1a: // SUB (substitute)
- return 1;
- */
- case 0x1b: // ESC (escape)
- ty->state.had_cr = 0;
- return _handle_esc(ty, c, ce);
-/*
- case 0x1c: // FS (file separator)
- return 1;
- case 0x1d: // GS (group separator)
- return 1;
- case 0x1e: // RS (record separator)
- return 1;
- case 0x1f: // US (unit separator)
- return 1;
- */
- default:
- ERR("unhandled char 0x%02x", c[0]);
- ty->state.had_cr = 0;
- return 1;
- }
- }
- else if (c[0] == 0x7f) // DEL
- {
- ERR("unhandled char 0x%02x [DEL]", c[0]);
- ty->state.had_cr = 0;
- return 1;
- }
- else if (c[0] == 0x9b) // ANSI ESC!!!
- {
- int v;
-
- printf("ANSI CSI!!!!!\n");
- ty->state.had_cr = 0;
- v = _handle_esc_csi(ty, c + 1, ce);
- if (v == -2) return 0;
- return v + 1;
- }
-
- cc = (int *)c;
- DBG("txt: [");
- while ((cc < ce) && (*cc >= 0x20) && (*cc != 0x7f))
- {
- DBG("%c", *cc);
- cc++;
- len++;
- }
- DBG("]");
- _text_append(ty, c, len);
- ty->state.had_cr = 0;
- return len;
-}
-
-static void
_handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
{
Eina_Unicode *c, *ce, *b;
ce = c + ty->buflen;
while (c < ce)
{
- n = _handle_seq(ty, c, ce);
+ n = _termpty_handle_seq(ty, c, ce);
if (n == 0)
{
Eina_Unicode *tmp = ty->buf;
{
while (c < ce)
{
- n = _handle_seq(ty, c, ce);
+ n = _termpty_handle_seq(ty, c, ce);
if (n == 0)
{
bytes = ((char *)ce - (char *)c) + sizeof(Eina_Unicode);
ty->h = h;
ty->backmax = backscroll;
- _reset_state(ty);
+ _termpty_reset_state(ty);
ty->save = ty->state;
ty->swap = ty->state;
c1 = &(olds[y * oldw]);
c2 = &(ty->screen[y * ty->w]);
- _text_copy(ty, c1, c2, ww);
+ _termpty_text_copy(ty, c1, c2, ww);
c1 = &(olds2[y * oldw]);
c2 = &(ty->screen2[y * ty->w]);
- _text_copy(ty, c1, c2, ww);
+ _termpty_text_copy(ty, c1, c2, ww);
}
free(olds);
void termpty_write(Termpty *ty, const char *input, int len);
void termpty_resize(Termpty *ty, int w, int h);
void termpty_backscroll_set(Termpty *ty, int size);
+
+extern int _termpty_log_dom;
--- /dev/null
+#include "private.h"
+#include <Elementary.h>
+#include "termpty.h"
+#include "termptydbl.h"
+#include "termptyesc.h"
+#include "termptyops.h"
+#include "termptyext.h"
+
+#undef CRITICAL
+#undef ERR
+#undef WRN
+#undef INF
+#undef DBG
+
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
+
+static int
+_csi_arg_get(Eina_Unicode **ptr)
+{
+ Eina_Unicode *b = *ptr;
+ int octal = 0;
+ int sum = 0;
+
+ while ((*b) && (!isdigit(*b))) b++;
+ if (!*b)
+ {
+ *ptr = NULL;
+ return 0;
+ }
+ if (*b == '0') octal = 1;
+ while (isdigit(*b))
+ {
+ if (octal) sum *= 8;
+ else sum *= 10;
+ sum += *b - '0';
+ b++;
+ }
+ *ptr = b;
+ return sum;
+}
+
+static int
+_handle_esc_csi(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
+{
+ Eina_Unicode *cc;
+ int arg, first = 1, i;
+ Eina_Unicode buf[4096], *b;
+
+ cc = (Eina_Unicode *)c;
+ b = buf;
+ while ((cc < ce) && (*cc >= '0') && (*cc <= '?'))
+ {
+ *b = *cc;
+ b++;
+ cc++;
+ }
+ // if cc == ce then we got to the end of the string with no end marker
+ // so return -2 to indicate to go back to the escape beginning when
+ // there is more bufer available
+ if (cc == ce) return -2;
+ *b = 0;
+ b = buf;
+// DBG(" CSI: '%c' args '%s'", *cc, buf);
+ switch (*cc)
+ {
+ case 'm': // color set
+ while (b)
+ {
+ arg = _csi_arg_get(&b);
+ if ((first) && (!b))
+ _termpty_reset_att(&(ty->state.att));
+ else if (b)
+ {
+ first = 0;
+ switch (arg)
+ {
+ case 0: // reset to normal
+ _termpty_reset_att(&(ty->state.att));
+ break;
+ case 1: // bold/bright
+ ty->state.att.bold = 1;
+ break;
+ case 2: // faint
+ ty->state.att.faint = 1;
+ break;
+ case 3: // italic
+#if defined(SUPPORT_ITALIC)
+ ty->state.att.italic = 1;
+#endif
+ break;
+ case 4: // underline
+ ty->state.att.underline = 1;
+ break;
+ case 5: // blink
+ ty->state.att.blink = 1;
+ break;
+ case 6: // blink rapid
+ ty->state.att.blink2 = 1;
+ break;
+ case 7: // reverse
+ ty->state.att.inverse = 1;
+ break;
+ case 8: // invisible
+ ty->state.att.invisible = 1;
+ break;
+ case 9: // strikethrough
+ ty->state.att.strike = 1;
+ break;
+ case 21: // no bold/bright
+ ty->state.att.bold = 0;
+ break;
+ case 22: // no faint
+ ty->state.att.faint = 0;
+ break;
+ case 23: // no italic
+#if defined(SUPPORT_ITALIC)
+ ty->state.att.italic = 0;
+#endif
+ break;
+ case 24: // no underline
+ ty->state.att.underline = 0;
+ break;
+ case 25: // no blink
+ ty->state.att.blink = 0;
+ ty->state.att.blink2 = 0;
+ break;
+ case 27: // no reverse
+ ty->state.att.inverse = 0;
+ break;
+ case 28: // no invisible
+ ty->state.att.invisible = 0;
+ break;
+ case 29: // no strikethrough
+ ty->state.att.strike = 0;
+ break;
+ case 30: // fg
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ ty->state.att.fg256 = 0;
+ ty->state.att.fg = (arg - 30) + COL_BLACK;
+ ty->state.att.fgintense = 0;
+ break;
+ case 38: // xterm 256 fg color ???
+ // now check if next arg is 5
+ arg = _csi_arg_get(&b);
+ if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
+ else
+ {
+ // then get next arg - should be color index 0-255
+ arg = _csi_arg_get(&b);
+ if (!b) ERR("Failed xterm 256 color fg esc val");
+ else
+ {
+ ty->state.att.fg256 = 1;
+ ty->state.att.fg = arg;
+ }
+ }
+ ty->state.att.fgintense = 0;
+ break;
+ case 39: // default fg color
+ ty->state.att.fg256 = 0;
+ ty->state.att.fg = COL_DEF;
+ ty->state.att.fgintense = 0;
+ break;
+ case 40: // bg
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ ty->state.att.bg256 = 0;
+ ty->state.att.bg = (arg - 40) + COL_BLACK;
+ ty->state.att.bgintense = 0;
+ break;
+ case 48: // xterm 256 bg color ???
+ // now check if next arg is 5
+ arg = _csi_arg_get(&b);
+ if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
+ else
+ {
+ // then get next arg - should be color index 0-255
+ arg = _csi_arg_get(&b);
+ if (!b) ERR("Failed xterm 256 color bg esc val");
+ else
+ {
+ ty->state.att.bg256 = 1;
+ ty->state.att.bg = arg;
+ }
+ }
+ ty->state.att.bgintense = 0;
+ break;
+ case 49: // default bg color
+ ty->state.att.bg256 = 0;
+ ty->state.att.bg = COL_DEF;
+ ty->state.att.bgintense = 0;
+ break;
+ case 90: // fg
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ ty->state.att.fg256 = 0;
+ ty->state.att.fg = (arg - 90) + COL_BLACK;
+ ty->state.att.fgintense = 1;
+ break;
+ case 98: // xterm 256 fg color ???
+ // now check if next arg is 5
+ arg = _csi_arg_get(&b);
+ if (arg != 5) ERR("Failed xterm 256 color fg esc 5");
+ else
+ {
+ // then get next arg - should be color index 0-255
+ arg = _csi_arg_get(&b);
+ if (!b) ERR("Failed xterm 256 color fg esc val");
+ else
+ {
+ ty->state.att.fg256 = 1;
+ ty->state.att.fg = arg;
+ }
+ }
+ ty->state.att.fgintense = 1;
+ break;
+ case 99: // default fg color
+ ty->state.att.fg256 = 0;
+ ty->state.att.fg = COL_DEF;
+ ty->state.att.fgintense = 1;
+ break;
+ case 100: // bg
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ ty->state.att.bg256 = 0;
+ ty->state.att.bg = (arg - 100) + COL_BLACK;
+ ty->state.att.bgintense = 1;
+ break;
+ case 108: // xterm 256 bg color ???
+ // now check if next arg is 5
+ arg = _csi_arg_get(&b);
+ if (arg != 5) ERR("Failed xterm 256 color bg esc 5");
+ else
+ {
+ // then get next arg - should be color index 0-255
+ arg = _csi_arg_get(&b);
+ if (!b) ERR("Failed xterm 256 color bg esc val");
+ else
+ {
+ ty->state.att.bg256 = 1;
+ ty->state.att.bg = arg;
+ }
+ }
+ ty->state.att.bgintense = 1;
+ break;
+ case 109: // default bg color
+ ty->state.att.bg256 = 0;
+ ty->state.att.bg = COL_DEF;
+ ty->state.att.bgintense = 1;
+ break;
+ default: // not handled???
+ ERR(" color cmd [%i] not handled", arg);
+ break;
+ }
+ }
+ }
+ break;
+ case '@': // insert N blank chars
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ {
+ int pi = ty->state.insert;
+ int blank[1] = { ' ' };
+ int cx = ty->state.cx;
+
+ ty->state.wrapnext = 0;
+ ty->state.insert = 1;
+ for (i = 0; i < arg; i++)
+ _termpty_text_append(ty, blank, 1);
+ ty->state.insert = pi;
+ ty->state.cx = cx;
+ }
+ break;
+ case 'A': // cursor up N
+ case 'e': // cursor up N
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ for (i = 0; i < arg; i++)
+ {
+ ty->state.cy--;
+ _termpty_text_scroll_rev_test(ty);
+ }
+ break;
+ case 'B': // cursor down N
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ for (i = 0; i < arg; i++)
+ {
+ ty->state.cy++;
+ _termpty_text_scroll_test(ty);
+ }
+ break;
+ case 'D': // cursor left N
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ for (i = 0; i < arg; i++)
+ {
+ ty->state.cx--;
+ if (ty->state.cx < 0) ty->state.cx = 0;
+ }
+ break;
+ case 'C': // cursor right N
+ case 'a': // cursor right N
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ for (i = 0; i < arg; i++)
+ {
+ ty->state.cx++;
+ if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
+ }
+ break;
+ case 'H': // cursor pos set
+ case 'f': // cursor pos set
+ ty->state.wrapnext = 0;
+ if (!*b)
+ {
+ ty->state.cx = 0;
+ ty->state.cy = 0;
+ }
+ else
+ {
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ arg--;
+ if (arg < 0) arg = 0;
+ else if (arg >= ty->h) arg = ty->h - 1;
+ if (b) ty->state.cy = arg;
+ if (b)
+ {
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ arg--;
+ }
+ else arg = 0;
+ if (arg < 0) arg = 0;
+ else if (arg >= ty->w) arg = ty->w - 1;
+ if (b) ty->state.cx = arg;
+ }
+ break;
+ case 'G': // to column N
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ ty->state.cx = arg - 1;
+ if (ty->state.cx < 0) ty->state.cx = 0;
+ else if (ty->state.cx >= ty->w) ty->state.cx = ty->w - 1;
+ break;
+ case 'd': // to row N
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ ty->state.cy = arg - 1;
+ if (ty->state.cy < 0) ty->state.cy = 0;
+ else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
+ break;
+ case 'E': // down relative N rows, and to col 0
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ ty->state.cy += arg;
+ if (ty->state.cy < 0) ty->state.cy = 0;
+ else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
+ ty->state.cx = 0;
+ break;
+ case 'F': // up relative N rows, and to col 0
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ ty->state.wrapnext = 0;
+ ty->state.cy -= arg;
+ if (ty->state.cy < 0) ty->state.cy = 0;
+ else if (ty->state.cy >= ty->h) ty->state.cy = ty->h - 1;
+ ty->state.cx = 0;
+ break;
+ case 'X': // erase N chars
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ _termpty_clear_line(ty, TERMPTY_CLR_END, arg);
+ break;
+ case 'S': // scroll up N lines
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ for (i = 0; i < arg; i++) _termpty_text_scroll(ty);
+ break;
+ case 'T': // scroll down N lines
+ arg = _csi_arg_get(&b);
+ if (arg < 1) arg = 1;
+ for (i = 0; i < arg; i++) _termpty_text_scroll_rev(ty);
+ break;
+ case 'M': // delete N lines - cy
+ case 'L': // insert N lines - cy
+ arg = _csi_arg_get(&b);
+ {
+ int sy1, sy2;
+
+ sy1 = ty->state.scroll_y1;
+ sy2 = ty->state.scroll_y2;
+ if (ty->state.scroll_y2 == 0)
+ {
+ ty->state.scroll_y1 = ty->state.cy;
+ ty->state.scroll_y2 = ty->h;
+ }
+ else
+ {
+ ty->state.scroll_y1 = ty->state.cy;
+ if (ty->state.scroll_y2 <= ty->state.scroll_y1)
+ ty->state.scroll_y2 = ty->state.scroll_y1 + 1;
+ }
+ if (arg < 1) arg = 1;
+ for (i = 0; i < arg; i++)
+ {
+ if (*cc == 'M') _termpty_text_scroll(ty);
+ else _termpty_text_scroll_rev(ty);
+ }
+ ty->state.scroll_y1 = sy1;
+ ty->state.scroll_y2 = sy2;
+ }
+ break;
+ case 'P': // erase and scrollback N chars
+ arg = _csi_arg_get(&b);
+ {
+ Termcell *cells;
+ int x, lim;
+
+ if (arg < 1) arg = 1;
+ cells = &(ty->screen[ty->state.cy * ty->w]);
+ lim = ty->w - arg;
+ for (x = ty->state.cx; x < (ty->w); x++)
+ {
+ if (x < lim)
+ cells[x] = cells[x + arg];
+ else
+ memset(&(cells[x]), 0, sizeof(*cells));
+ }
+ }
+ break;
+ case 'c': // query device id
+ {
+ char bf[32];
+// 0 Base VT100, no options
+// 1 Preprocessor option (STP)
+// 2 Advanced video option (AVO)
+// 3 AVO and STP
+// 4 Graphics processor option (GO)
+// 5 GO and STP
+// 6 GO and AVO
+// 7 GO, STP, and AVO
+ snprintf(bf, sizeof(bf), "\033[?1;%ic", 0);
+ termpty_write(ty, bf, strlen(bf));
+ }
+ break;
+ case 'J': // "2j" erases the screen, 1j erase from screen start to curs, 0j erase cursor to end of screen
+ arg = _csi_arg_get(&b);
+ if (b)
+ {
+ if ((arg >= TERMPTY_CLR_END) && (arg <= TERMPTY_CLR_ALL))
+ _termpty_clear_screen(ty, arg);
+ else
+ ERR("invalid clr scr %i", arg);
+ }
+ else _termpty_clear_screen(ty, TERMPTY_CLR_END);
+ break;
+ case 'K': // 0K erase to end of line, 1K erase from screen start to cursor, 2K erase all of line
+ arg = _csi_arg_get(&b);
+ if (b)
+ {
+ if ((arg >= TERMPTY_CLR_END) && (arg <= TERMPTY_CLR_ALL))
+ _termpty_clear_line(ty, arg, ty->w);
+ else
+ ERR("invalid clr lin %i", arg);
+ }
+ else _termpty_clear_line(ty, TERMPTY_CLR_END, ty->w);
+ break;
+ case 'h': // list - set screen mode or line wrap ("7h" == turn on line wrap, "7l" disables line wrap , ...)
+ case 'l':
+ {
+ int mode = 0, priv = 0;
+ int handled = 0;
+
+ if (*cc == 'h') mode = 1;
+ if (*b == '?')
+ {
+ priv = 1;
+ b++;
+ }
+ if (priv)
+ {
+ while (b)
+ {
+ arg = _csi_arg_get(&b);
+ if (b)
+ {
+ int size;
+
+ // complete-ish list here:
+ // http://ttssh2.sourceforge.jp/manual/en/about/ctrlseq.html
+ switch (arg)
+ {
+ case 1:
+ handled = 1;
+ ty->state.appcursor = mode;
+ break;
+ case 2:
+ handled = 1;
+ ty->state.kbd_lock = mode;
+ break;
+ case 3: // should we handle this?
+ handled = 1;
+ ERR("XXX: 132 column mode %i", mode);
+ break;
+ case 4:
+ handled = 1;
+ ERR("XXX: set insert mode to %i", mode);
+ break;
+ case 5:
+ handled = 1;
+ ty->state.reverse = mode;
+ break;
+ case 6:
+ handled = 1;
+ ERR("XXX: origin mode: cursor is at 0,0/cursor limited to screen/start point for line #'s depends on top margin");
+ break;
+ case 7:
+ handled = 1;
+ DBG("DDD: set wrap mode to %i", mode);
+ ty->state.wrap = mode;
+ break;
+ case 8:
+ handled = 1;
+ ty->state.no_autorepeat = !mode;
+ INF("XXX: auto repeat %i", mode);
+ break;
+ case 9:
+ handled = 1;
+ if (mode) ty->mouse_rep = MOUSE_X10;
+ else ty->mouse_rep = MOUSE_OFF;
+ break;
+ case 12: // ignore
+ handled = 1;
+// DBG("XXX: set blinking cursor to (stop?) %i or local echo", mode);
+ break;
+ case 19: // never seen this - what to do?
+ handled = 1;
+// INF("XXX: set print extent to full screen");
+ break;
+ case 20: // crfl==1 -> cur moves to col 0 on LF, FF or VT, ==0 -> mode is cr+lf
+ handled = 1;
+ ty->state.crlf = mode;
+ break;
+ case 25:
+ handled = 1;
+ ty->state.hidecursor = !mode;
+ break;
+ case 30: // ignore
+ handled = 1;
+// DBG("XXX: set scrollbar mapping %i", mode);
+ break;
+ case 33: // ignore
+ handled = 1;
+// INF("XXX: Stop cursor blink %i", mode);
+ break;
+ case 34: // ignore
+ handled = 1;
+// INF("XXX: Underline cursor mode %i", mode);
+ break;
+ case 35: // ignore
+ handled = 1;
+// DBG("XXX: set shift keys %i", mode);
+ break;
+ case 38: // ignore
+ handled = 1;
+// INF("XXX: switch to tek window %i", mode);
+ break;
+ case 59: // ignore
+ handled = 1;
+// INF("XXX: kanji terminal mode %i", mode);
+ break;
+ case 66:
+ handled = 1;
+ ERR("XXX: app keypad mode %i", mode);
+ break;
+ case 67:
+ handled = 1;
+ ty->state.send_bs = mode;
+ INF("XXX: backspace send bs not del = %i", mode);
+ break;
+ case 1000:
+ handled = 1;
+ if (mode) ty->mouse_rep = MOUSE_NORMAL;
+ else ty->mouse_rep = MOUSE_OFF;
+ INF("XXX: set mouse (press+release only) to %i", mode);
+ break;
+ case 1001:
+ handled = 1;
+ ERR("XXX: x11 mouse highlighting %i", mode);
+ break;
+ case 1002:
+ handled = 1;
+ ERR("XXX: set mouse (press+relese+motion while pressed) %i", mode);
+ break;
+ case 1003:
+ handled = 1;
+ ERR("XXX: set mouse (press+relese+all motion) %i", mode);
+ break;
+ case 1004: // i dont know what focus repporting is?
+ handled = 1;
+ ERR("XXX: enable focus reporting %i", mode);
+ break;
+ case 1005:
+ handled = 1;
+ if (mode) ty->mouse_rep = MOUSE_UTF8;
+ else ty->mouse_rep = MOUSE_OFF;
+ INF("XXX: set mouse (xterm utf8 style) %i", mode);
+ break;
+ case 1006:
+ handled = 1;
+ if (mode) ty->mouse_rep = MOUSE_SGR;
+ else ty->mouse_rep = MOUSE_OFF;
+ INF("XXX: set mouse (xterm sgr style) %i", mode);
+ break;
+ case 1010: // ignore
+ handled = 1;
+// DBG("XXX: set home on tty output %i", mode);
+ break;
+ case 1012: // ignore
+ handled = 1;
+// DBG("XXX: set home on tty input %i", mode);
+ break;
+ case 1015:
+ handled = 1;
+ if (mode) ty->mouse_rep = MOUSE_URXVT;
+ else ty->mouse_rep = MOUSE_OFF;
+ INF("XXX: set mouse (rxvt-unicdode style) %i", mode);
+ break;
+ case 1034: // ignore
+ /* libreadline6 emits it but it shouldn't.
+ See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=577012
+ */
+ handled = 1;
+// DBG("Ignored screen mode %i", arg);
+ break;
+ case 1047:
+ case 1049:
+ case 47:
+ handled = 1;
+ DBG("DDD: switch buf");
+ if (ty->altbuf)
+ {
+ // if we are looking at alt buf now,
+ // clear main buf before we swap it back
+ // into the sreen2 save (so save is
+ // clear)
+ _termpty_clear_all(ty);
+// _termpty_cursor_copy(&(ty->swap), &(ty->state));
+ ty->state = ty->swap;
+ }
+ else
+ {
+// _termpty_cursor_copy(&(ty->state), &(ty->swap));
+ ty->swap = ty->state;
+ }
+ size = ty->w * ty->h;
+ // swap screen content now
+ for (i = 0; i < size; i++)
+ {
+ Termcell t;
+
+ t = ty->screen[i];
+ ty->screen[i] = ty->screen2[i];
+ ty->screen2[i] = t;
+ }
+ ty->altbuf = !ty->altbuf;
+ if (ty->cb.cancel_sel.func)
+ ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+ break;
+ case 1048:
+ if (mode)
+ _termpty_cursor_copy(&(ty->state), &(ty->save));
+ else
+ _termpty_cursor_copy(&(ty->save), &(ty->state));
+ break;
+ case 2004: // ignore
+ handled = 1;
+// INF("XXX: enable bracketed paste mode %i", mode);
+ break;
+ case 7727: // ignore
+ handled = 1;
+// INF("XXX: enable application escape mode %i", mode);
+ break;
+ case 7786: // ignore
+ handled = 1;
+// INF("XXX: enable mouse wheel -> cursor key xlation %i", mode);
+ break;
+ default:
+ ERR("unhandled screen mode arg %i", arg);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ while (b)
+ {
+ arg = _csi_arg_get(&b);
+ if (b)
+ {
+ if (arg == 1)
+ {
+ handled = 1;
+ ty->state.appcursor = mode;
+ }
+ else if (arg == 4)
+ {
+ handled = 1;
+ DBG("DDD: set insert mode to %i", mode);
+ ty->state.insert = mode;
+ }
+// else if (arg == 24)
+// {
+// ERR("unhandled #24 arg %i", arg);
+// // ???
+// }
+ else
+ ERR("unhandled screen non-priv mode arg %i, mode %i, ch '%c'", arg, mode, *cc);
+ }
+ }
+ }
+ if (!handled) ERR("unhandled '%c'", *cc);
+ }
+ break;
+ case 'r':
+ arg = _csi_arg_get(&b);
+ if (!b)
+ {
+ INF("no region args reset region");
+ ty->state.scroll_y1 = 0;
+ ty->state.scroll_y2 = 0;
+ }
+ else
+ {
+ int arg2;
+
+ arg2 = _csi_arg_get(&b);
+ if (!b)
+ {
+ INF("failed to give 2 region args reset region");
+ ty->state.scroll_y1 = 0;
+ ty->state.scroll_y2 = 0;
+ }
+ else
+ {
+ if (arg > arg2)
+ {
+ ERR("scroll region beginning > end [%i %i]", arg, arg2);
+ ty->state.scroll_y1 = 0;
+ ty->state.scroll_y2 = 0;
+ }
+ else
+ {
+ INF("2 region args: %i %i", arg, arg2);
+ if (arg >= ty->h) arg = ty->h - 1;
+ if (arg2 > ty->h) arg2 = ty->h;
+ arg2++;
+ ty->state.scroll_y1 = arg - 1;
+ ty->state.scroll_y2 = arg2 - 1;
+ }
+ }
+ }
+ break;
+ case 's': // store cursor pos
+ _termpty_cursor_copy(&(ty->state), &(ty->save));
+ break;
+ case 'u': // restore cursor pos
+ _termpty_cursor_copy(&(ty->save), &(ty->state));
+ break;
+/*
+ case 'R': // report cursor
+ break;
+ case 'n': // "6n" queires cursor pos, 0n, 3n, 5n too
+ break;
+ case 's':
+ break;
+ case 't':
+ break;
+ case 'p': // define key assignments based on keycode
+ break;
+ case 'q': // set/clear led's
+ break;
+ case 'x': // request terminal parameters
+ break;
+ case 'r': // set top and bottom margins
+ break;
+ case 'y': // invoke confidence test
+ break;
+ case 'g': // clear tabulation
+ break;
+ */
+ default:
+ ERR("unhandled CSI '%c' (0x%02x)", *cc, *cc);
+ break;
+ }
+ cc++;
+ return cc - c;
+}
+
+static int
+_handle_esc_xterm(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
+{
+ Eina_Unicode *cc;
+ Eina_Unicode buf[4096], *b;
+ char *s;
+ int len = 0;
+
+ cc = (Eina_Unicode *)c;
+ b = buf;
+ while ((cc < ce) && (*cc >= ' ') && (*cc < 0x7f))
+ {
+ *b = *cc;
+ b++;
+ cc++;
+ }
+ *b = 0;
+ if ((*cc < ' ') || (*cc >= 0x7f)) cc++;
+ else return -2;
+ switch (buf[0])
+ {
+ case '0':
+ // XXX: title + name - callback
+ s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
+ if (ty->prop.title) eina_stringshare_del(ty->prop.title);
+ if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
+ if (b)
+ {
+ ty->prop.title = eina_stringshare_add(s);
+ ty->prop.icon = eina_stringshare_add(s);
+ free(s);
+ }
+ else
+ {
+ ty->prop.title = NULL;
+ ty->prop.icon = NULL;
+ }
+ if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
+ if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
+ break;
+ case '1':
+ // XXX: icon name - callback
+ s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
+ if (ty->prop.icon) eina_stringshare_del(ty->prop.icon);
+ if (s)
+ {
+ ty->prop.icon = eina_stringshare_add(s);
+ free(s);
+ }
+ else
+ {
+ ty->prop.icon = NULL;
+ }
+ if (ty->cb.set_icon.func) ty->cb.set_title.func(ty->cb.set_icon.data);
+ break;
+ case '2':
+ // XXX: title - callback
+ s = eina_unicode_unicode_to_utf8(&(buf[2]), &len);
+ if (ty->prop.title) eina_stringshare_del(ty->prop.title);
+ if (s)
+ {
+ ty->prop.title = eina_stringshare_add(s);
+ free(s);
+ }
+ else
+ {
+ ty->prop.title = NULL;
+ }
+ if (ty->cb.set_title.func) ty->cb.set_title.func(ty->cb.set_title.data);
+ break;
+ case '4':
+ // XXX: set palette entry. not supported.
+ b = &(buf[2]);
+ break;
+ default:
+ // many others
+ ERR("unhandled xterm esc '%c'", buf[0]);
+ break;
+ }
+ return cc - c;
+}
+
+static int
+_handle_esc_terminology(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
+{
+ Eina_Unicode *cc;
+ Eina_Unicode buf[4096], *b;
+ char *s;
+ int slen = 0;
+
+ cc = (Eina_Unicode *)c;
+ b = buf;
+ while ((cc < ce) && (*cc != 0x0))
+ {
+ *b = *cc;
+ b++;
+ cc++;
+ }
+ *b = 0;
+ if (*cc == 0x0) cc++;
+ else return -2;
+ // commands are stored in the buffer, 0 bytes not allowd (end marker)
+ s = eina_unicode_unicode_to_utf8(buf, &slen);
+ ty->cur_cmd = s;
+ if (ty->cb.command.func) ty->cb.command.func(ty->cb.command.data);
+ ty->cur_cmd = NULL;
+ if (s) free(s);
+ return cc - c;
+}
+
+static int
+_handle_esc(Termpty *ty, const Eina_Unicode *c, Eina_Unicode *ce)
+{
+ if ((ce - c) < 2) return 0;
+ DBG("ESC: '%c'", c[1]);
+ switch (c[1])
+ {
+ case '[':
+ return 2 + _handle_esc_csi(ty, c + 2, ce);
+ case ']':
+ return 2 + _handle_esc_xterm(ty, c + 2, ce);
+ case '}':
+ return 2 + _handle_esc_terminology(ty, c + 2, ce);
+ case '=': // set alternate keypad mode
+ ty->state.alt_kp = 1;
+ return 2;
+ case '>': // set numeric keypad mode
+ ty->state.alt_kp = 0;
+ return 2;
+ case 'M': // move to prev line
+ ty->state.wrapnext = 0;
+ ty->state.cy--;
+ _termpty_text_scroll_rev_test(ty);
+ return 2;
+ case 'D': // move to next line
+ ty->state.wrapnext = 0;
+ ty->state.cy++;
+ _termpty_text_scroll_test(ty);
+ return 2;
+ case 'E': // add \n\r
+ ty->state.wrapnext = 0;
+ ty->state.cx = 0;
+ ty->state.cy++;
+ _termpty_text_scroll_test(ty);
+ return 2;
+ case 'Z': // same a 'ESC [ Pn c'
+ _term_txt_write(ty, "\033[?1;2C");
+ return 2;
+ case 'c': // reset terminal to initial state
+ DBG("reset to init mode and clear");
+ _termpty_reset_state(ty);
+ _termpty_clear_screen(ty, TERMPTY_CLR_ALL);
+ if (ty->cb.cancel_sel.func)
+ ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+ return 2;
+ case '(': // charset 0
+ ty->state.chset[0] = c[2];
+ ty->state.multibyte = 0;
+ ty->state.charsetch = c[2];
+ return 3;
+ case ')': // charset 1
+ ty->state.chset[1] = c[2];
+ ty->state.multibyte = 0;
+ return 3;
+ case '*': // charset 2
+ ty->state.chset[2] = c[2];
+ ty->state.multibyte = 0;
+ return 3;
+ case '+': // charset 3
+ ty->state.chset[3] = c[2];
+ ty->state.multibyte = 0;
+ return 3;
+ case '$': // charset -2
+ ty->state.chset[2] = c[2];
+ ty->state.multibyte = 1;
+ return 3;
+ case '#': // #8 == test mode -> fill screen with "E";
+ if (c[2] == '8')
+ {
+ int i, size;
+ Termcell *cells;
+
+ DBG("reset to init mode and clear then fill with E");
+ _termpty_reset_state(ty);
+ ty->save = ty->state;
+ ty->swap = ty->state;
+ _termpty_clear_screen(ty, TERMPTY_CLR_ALL);
+ if (ty->cb.cancel_sel.func)
+ ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+ cells = ty->screen;
+ size = ty->w * ty->h;
+ if (cells)
+ {
+ for (i = 0; i < size; i++) cells[i].codepoint = 'E';
+ }
+ }
+ return 3;
+ case '@': // just consume this plus next char
+ return 3;
+ case '7': // save cursor pos
+ _termpty_cursor_copy(&(ty->state), &(ty->save));
+ return 2;
+ case '8': // restore cursor pos
+ _termpty_cursor_copy(&(ty->save), &(ty->state));
+ return 2;
+/*
+ case 'G': // query gfx mode
+ return 3;
+ case 'H': // set tab at current column
+ return 2;
+ case 'n': // single shift 2
+ return 2;
+ case 'o': // single shift 3
+ return 2;
+ */
+ default:
+ ERR("eek - esc unhandled '%c' (0x%02x)", c[1], c[1]);
+ break;
+ }
+ return 1;
+}
+
+int
+_termpty_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce)
+{
+ Eina_Unicode *cc;
+ int len = 0;
+
+/*
+ printf(" B: ");
+ int j;
+ for (j = 0; c + j < ce && j < 100; j++)
+ {
+ if ((c[j] < ' ') || (c[j] >= 0x7f))
+ printf("\033[35m%02x\033[0m", c[j]);
+ else
+ printf("%c", c[j]);
+ }
+ printf("\n");
+ */
+ if (c[0] < 0x20)
+ {
+ switch (c[0])
+ {
+/*
+ case 0x00: // NUL
+ return 1;
+ case 0x01: // SOH (start of heading)
+ return 1;
+ case 0x02: // STX (start of text)
+ return 1;
+ case 0x03: // ETX (end of text)
+ return 1;
+ case 0x04: // EOT (end of transmission)
+ return 1;
+ */
+ case 0x05: // ENQ (enquiry)
+ _term_txt_write(ty, "ABC\r\n");
+ ty->state.had_cr = 0;
+ return 1;
+/*
+ case 0x06: // ACK (acknowledge)
+ return 1;
+ */
+ case 0x07: // BEL '\a' (bell)
+ if (ty->cb.bell.func) ty->cb.bell.func(ty->cb.bell.data);
+ ty->state.had_cr = 0;
+ return 1;
+ case 0x08: // BS '\b' (backspace)
+ DBG("->BS");
+ ty->state.wrapnext = 0;
+ ty->state.cx--;
+ if (ty->state.cx < 0) ty->state.cx = 0;
+ ty->state.had_cr = 0;
+ return 1;
+ case 0x09: // HT '\t' (horizontal tab)
+ DBG("->HT");
+ ty->screen[ty->state.cx + (ty->state.cy * ty->w)].att.tab = 1;
+ ty->state.wrapnext = 0;
+ ty->state.cx += 8;
+ ty->state.cx = (ty->state.cx / 8) * 8;
+ if (ty->state.cx >= ty->w)
+ ty->state.cx = ty->w - 1;
+ ty->state.had_cr = 0;
+ return 1;
+ case 0x0a: // LF '\n' (new line)
+ case 0x0b: // VT '\v' (vertical tab)
+ case 0x0c: // FF '\f' (form feed)
+ DBG("->LF");
+ if (ty->state.had_cr)
+ ty->screen[ty->state.had_cr_x + (ty->state.had_cr_y * ty->w)].att.newline = 1;
+ ty->state.wrapnext = 0;
+ if (ty->state.crlf) ty->state.cx = 0;
+ ty->state.cy++;
+ _termpty_text_scroll_test(ty);
+ ty->state.had_cr = 0;
+ return 1;
+ case 0x0d: // CR '\r' (carriage ret)
+ DBG("->CR");
+ if (ty->state.cx != 0)
+ {
+ ty->state.had_cr_x = ty->state.cx;
+ ty->state.had_cr_y = ty->state.cy;
+ }
+ ty->state.wrapnext = 0;
+ ty->state.cx = 0;
+ ty->state.had_cr = 1;
+ return 1;
+
+ case 0x0e: // SO (shift out) // Maps G1 character set into GL.
+ ty->state.charset = 1;
+ ty->state.charsetch = ty->state.chset[1];
+ return 1;
+ case 0x0f: // SI (shift in) // Maps G0 character set into GL.
+ ty->state.charset = 0;
+ ty->state.charsetch = ty->state.chset[0];
+ return 1;
+/*
+ case 0x10: // DLE (data link escape)
+ return 1;
+ case 0x11: // DC1 (device control 1)
+ return 1;
+ case 0x12: // DC2 (device control 2)
+ return 1;
+ case 0x13: // DC3 (device control 3)
+ return 1;
+ case 0x14: // DC4 (device control 4)
+ return 1;
+ case 0x15: // NAK (negative ack.)
+ return 1;
+ case 0x16: // SYN (synchronous idle)
+ return 1;
+ case 0x17: // ETB (end of trans. blk)
+ return 1;
+ case 0x18: // CAN (cancel)
+ return 1;
+ case 0x19: // EM (end of medium)
+ return 1;
+ case 0x1a: // SUB (substitute)
+ return 1;
+ */
+ case 0x1b: // ESC (escape)
+ ty->state.had_cr = 0;
+ return _handle_esc(ty, c, ce);
+/*
+ case 0x1c: // FS (file separator)
+ return 1;
+ case 0x1d: // GS (group separator)
+ return 1;
+ case 0x1e: // RS (record separator)
+ return 1;
+ case 0x1f: // US (unit separator)
+ return 1;
+ */
+ default:
+ ERR("unhandled char 0x%02x", c[0]);
+ ty->state.had_cr = 0;
+ return 1;
+ }
+ }
+ else if (c[0] == 0x7f) // DEL
+ {
+ ERR("unhandled char 0x%02x [DEL]", c[0]);
+ ty->state.had_cr = 0;
+ return 1;
+ }
+ else if (c[0] == 0x9b) // ANSI ESC!!!
+ {
+ int v;
+
+ printf("ANSI CSI!!!!!\n");
+ ty->state.had_cr = 0;
+ v = _handle_esc_csi(ty, c + 1, ce);
+ if (v == -2) return 0;
+ return v + 1;
+ }
+
+ cc = (int *)c;
+ DBG("txt: [");
+ while ((cc < ce) && (*cc >= 0x20) && (*cc != 0x7f))
+ {
+ DBG("%c", *cc);
+ cc++;
+ len++;
+ }
+ DBG("]");
+ _termpty_text_append(ty, c, len);
+ ty->state.had_cr = 0;
+ return len;
+}
--- /dev/null
+int _termpty_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce);
+
--- /dev/null
+#include "private.h"
+#include <Elementary.h>
+#include "termpty.h"
+#include "termptyops.h"
+
+#undef CRITICAL
+#undef ERR
+#undef WRN
+#undef INF
+#undef DBG
+
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
+
+//// extended terminology escape handling goes in here
+//
+// this is where escapes get handled *IF* the termpty layer needs to interpret
+// them itself for some reason. if it returns EINA_FALSE, it means the escape
+// is to be passed onto termio layer as a callback and handled there after
+// this code. an extended escape may be handled in here exclusively (return
+// EINA_TRUE), handled here first, then in termio (EINA_FALSE return) or not
+// handled here at all and just passed to termio to figure it out (return
+// EINA_FALSE).
+//
+// command strings like like this:
+// axBLAHBLAH
+// where 'a' is the major opcode char.
+// and 'x' is the minor opcode char.
+// and 'BLAHBLAH' is an optional data payload string
+
+static Eina_Bool
+_handle_op_a(Termpty *ty __UNUSED__, const char *txt, Eina_Unicode *utxt __UNUSED__)
+{
+ switch (txt[1])
+ {
+ case 'a': // command aa*
+ break;
+ // room here for more minor opcode chars like 'b', 'c' etc.
+ default:
+ break;
+ }
+ return EINA_FALSE;
+}
+
+Eina_Bool
+_termpty_ext_handle(Termpty *ty, const char *txt, Eina_Unicode *utxt)
+{
+ switch (txt[0]) // major opcode
+ {
+ case 'a': // command a*
+ return _handle_op_a(ty, txt, utxt);
+ break;
+ // room here for more major opcode chars like 'b', 'c' etc.
+ default:
+ break;
+ }
+ return EINA_FALSE;
+}
--- /dev/null
+Eina_Bool _termpty_ext_handle(Termpty *ty, const char *txt, Eina_Unicode *utxt);
+
--- /dev/null
+#include "private.h"
+#include <Elementary.h>
+#include "termptygfx.h"
+
+/* translates VT100 ACS escape codes to Unicode values.
+ * Based on rxvt-unicode screen.C table.
+ */
+static const unsigned short vt100_to_unicode[62] =
+{
+// ? ? ? ? ? ? ?
+// A=UPARR B=DNARR C=RTARR D=LFARR E=FLBLK F=3/4BL G=SNOMN
+ 0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603,
+// H= I= J= K= L= M= N=
+ 0, 0, 0, 0, 0, 0, 0,
+// O= P= Q= R= S= T= U=
+ 0, 0, 0, 0, 0, 0, 0,
+// V= W= X= Y= Z= [= \=
+ 0, 0, 0, 0, 0, 0, 0,
+// ? ? v->0 v->1 v->2 v->3 v->4
+// ]= ^= _=SPC `=DIAMN a=HSMED b=HT c=FF
+ 0, 0, 0x0020, 0x25c6, 0x2592, 0x2409, 0x240c,
+// v->5 v->6 v->7 v->8 v->9 v->a v->b
+// d=CR e=LF f=DEGRE g=PLSMN h=NL i=VT j=SL-BR
+ 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518,
+// v->c v->d v->e v->f v->10 v->11 v->12
+// k=SL-TR l=SL-TL m=SL-BL n=SL-+ o=SL-T1 p=SL-T2 q=SL-HZ
+ 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, 0x23bb, 0x2500,
+// v->13 v->14 v->15 v->16 v->17 v->18 v->19
+// r=SL-T4 s=SL-T5 t=SL-VR u=SL-VL v=SL-HU w=Sl-HD x=SL-VT
+ 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502,
+// v->1a v->1b b->1c v->1d v->1e/a3 v->1f
+// y=LT-EQ z=GT-EQ {=PI |=NOTEQ }=POUND ~=DOT
+ 0x2264, 0x2265, 0x03c0, 0x2260, 0x20a4, 0x00b7
+};
+
+Eina_Unicode
+_termpty_charset_trans(Eina_Unicode g, int chset)
+{
+ switch (chset)
+ {
+ case '0': /* DEC Special Character & Line Drawing Set */
+ if ((g >= 0x41) && (g <= 0x7e) &&
+ (vt100_to_unicode[g - 0x41]))
+ return vt100_to_unicode[g - 0x41];
+ break;
+ case 'A': /* UK, replaces # with GBP */
+ if (g == '#') return 0x20a4;
+ break;
+ default:
+ break;
+ }
+ return g;
+}
--- /dev/null
+Eina_Unicode _termpty_charset_trans(Eina_Unicode g, int chset);
+
--- /dev/null
+#include "private.h"
+#include <Elementary.h>
+#include "termpty.h"
+#include "termptydbl.h"
+#include "termptyops.h"
+#include "termptygfx.h"
+
+#undef CRITICAL
+#undef ERR
+#undef WRN
+#undef INF
+#undef DBG
+
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_termpty_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_termpty_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_termpty_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_termpty_log_dom, __VA_ARGS__)
+#define DBG(...) EINA_LOG_DOM_DBG(_termpty_log_dom, __VA_ARGS__)
+
+static void
+_text_clear(Termpty *ty, Termcell *cells, int count, int val, Eina_Bool inherit_att)
+{
+ int i;
+ Termatt clear;
+
+ memset(&clear, 0, sizeof(clear));
+ if (inherit_att)
+ {
+ for (i = 0; i < count; i++)
+ {
+ cells[i].codepoint = val;
+ cells[i].att = ty->state.att;
+ }
+ }
+ else
+ {
+ for (i = 0; i < count; i++)
+ {
+ cells[i].codepoint = val;
+ cells[i].att = clear;
+ }
+ }
+}
+
+static void
+_text_save_top(Termpty *ty)
+{
+ Termsave *ts;
+
+ if (ty->backmax <= 0) return;
+ ts = malloc(sizeof(Termsave) + ((ty->w - 1) * sizeof(Termcell)));
+ ts->w = ty->w;
+ _termpty_text_copy(ty, ty->screen, ts->cell, ty->w);
+ if (!ty->back) ty->back = calloc(1, sizeof(Termsave *) * ty->backmax);
+ if (ty->back[ty->backpos]) free(ty->back[ty->backpos]);
+ ty->back[ty->backpos] = ts;
+ ty->backpos++;
+ if (ty->backpos >= ty->backmax) ty->backpos = 0;
+ ty->backscroll_num++;
+ if (ty->backscroll_num >= ty->backmax) ty->backscroll_num = ty->backmax - 1;
+}
+
+void
+_termpty_text_copy(Termpty *ty __UNUSED__, Termcell *cells, Termcell *dest, int count)
+{
+ memcpy(dest, cells, sizeof(*(cells)) * count);
+}
+
+void
+_termpty_text_scroll(Termpty *ty)
+{
+ Termcell *cells = NULL, *cells2;
+ int y, start_y = 0, end_y = ty->h - 1;
+
+ if (ty->state.scroll_y2 != 0)
+ {
+ start_y = ty->state.scroll_y1;
+ end_y = ty->state.scroll_y2 - 1;
+ }
+ else
+ {
+ if (!ty->altbuf)
+ {
+ _text_save_top(ty);
+ if (ty->cb.scroll.func) ty->cb.scroll.func(ty->cb.scroll.data);
+ }
+ else
+ if (ty->cb.cancel_sel.func)
+ ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+ }
+ DBG("... scroll!!!!! [%i->%i]", start_y, end_y);
+ cells2 = &(ty->screen[end_y * ty->w]);
+ for (y = start_y; y < end_y; y++)
+ {
+ cells = &(ty->screen[y * ty->w]);
+ cells2 = &(ty->screen[(y + 1) * ty->w]);
+ _termpty_text_copy(ty, cells2, cells, ty->w);
+ }
+ _text_clear(ty, cells2, ty->w, ' ', EINA_TRUE);
+}
+
+void
+_termpty_text_scroll_rev(Termpty *ty)
+{
+ Termcell *cells, *cells2 = NULL;
+ int y, start_y = 0, end_y = ty->h - 1;
+
+ if (ty->state.scroll_y2 != 0)
+ {
+ start_y = ty->state.scroll_y1;
+ end_y = ty->state.scroll_y2 - 1;
+ }
+ DBG("... scroll rev!!!!! [%i->%i]", start_y, end_y);
+ cells = &(ty->screen[end_y * ty->w]);
+ for (y = end_y; y > start_y; y--)
+ {
+ cells = &(ty->screen[(y - 1) * ty->w]);
+ cells2 = &(ty->screen[y * ty->w]);
+ _termpty_text_copy(ty, cells, cells2, ty->w);
+ }
+ _text_clear(ty, cells, ty->w, ' ', EINA_TRUE);
+}
+
+void
+_termpty_text_scroll_test(Termpty *ty)
+{
+ int e = ty->h;
+
+ if (ty->state.scroll_y2 != 0) e = ty->state.scroll_y2;
+ if (ty->state.cy >= e)
+ {
+ _termpty_text_scroll(ty);
+ ty->state.cy = e - 1;
+ }
+}
+
+void
+_termpty_text_scroll_rev_test(Termpty *ty)
+{
+ int b = 0;
+
+ if (ty->state.scroll_y2 != 0) b = ty->state.scroll_y1;
+ if (ty->state.cy < b)
+ {
+ _termpty_text_scroll_rev(ty);
+ ty->state.cy = b;
+ }
+}
+
+void
+_termpty_text_append(Termpty *ty, const Eina_Unicode *codepoints, int len)
+{
+ Termcell *cells;
+ int i, j;
+
+ cells = &(ty->screen[ty->state.cy * ty->w]);
+ for (i = 0; i < len; i++)
+ {
+ Eina_Unicode g;
+
+ if (ty->state.wrapnext)
+ {
+ cells[ty->state.cx].att.autowrapped = 1;
+ ty->state.wrapnext = 0;
+ ty->state.cx = 0;
+ ty->state.cy++;
+ _termpty_text_scroll_test(ty);
+ cells = &(ty->screen[ty->state.cy * ty->w]);
+ }
+ if (ty->state.insert)
+ {
+ for (j = ty->w - 1; j > ty->state.cx; j--)
+ cells[j] = cells[j - 1];
+ }
+
+ g = _termpty_charset_trans(codepoints[i], ty->state.charsetch);
+
+ cells[ty->state.cx].codepoint = g;
+ cells[ty->state.cx].att = ty->state.att;
+#if defined(SUPPORT_DBLWIDTH)
+ cells[ty->state.cx].att.dblwidth = _termpty_is_dblwidth_get(ty, g);
+ if ((cells[ty->state.cx].att.dblwidth) && (ty->state.cx < (ty->w - 1)))
+ {
+ cells[ty->state.cx + 1].codepoint = 0;
+ cells[ty->state.cx + 1].att = cells[ty->state.cx].att;
+ }
+#endif
+ if (ty->state.wrap)
+ {
+ ty->state.wrapnext = 0;
+#if defined(SUPPORT_DBLWIDTH)
+ if (cells[ty->state.cx].att.dblwidth)
+ {
+ if (ty->state.cx >= (ty->w - 2)) ty->state.wrapnext = 1;
+ else ty->state.cx += 2;
+ }
+ else
+ {
+ if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
+ else ty->state.cx++;
+ }
+#else
+ if (ty->state.cx >= (ty->w - 1)) ty->state.wrapnext = 1;
+ else ty->state.cx++;
+#endif
+ }
+ else
+ {
+ ty->state.wrapnext = 0;
+ ty->state.cx++;
+#if defined(SUPPORT_DBLWIDTH)
+ if (cells[ty->state.cx].att.dblwidth)
+ {
+ ty->state.cx++;
+ if (ty->state.cx >= (ty->w - 1))
+ ty->state.cx = ty->w - 2;
+ }
+ else
+ {
+ if (ty->state.cx >= ty->w)
+ ty->state.cx = ty->w - 1;
+ }
+#else
+ if (ty->state.cx >= ty->w)
+ ty->state.cx = ty->w - 1;
+#endif
+ }
+ }
+}
+
+void
+_termpty_clear_line(Termpty *ty, Termpty_Clear mode, int limit)
+{
+ Termcell *cells;
+ int n = 0;
+
+ cells = &(ty->screen[ty->state.cy * ty->w]);
+ switch (mode)
+ {
+ case TERMPTY_CLR_END:
+ n = ty->w - ty->state.cx;
+ cells = &(cells[ty->state.cx]);
+ break;
+ case TERMPTY_CLR_BEGIN:
+ n = ty->state.cx + 1;
+ break;
+ case TERMPTY_CLR_ALL:
+ n = ty->w;
+ break;
+ default:
+ return;
+ }
+ if (n > limit) n = limit;
+ _text_clear(ty, cells, n, 0, EINA_TRUE);
+}
+
+void
+_termpty_clear_screen(Termpty *ty, Termpty_Clear mode)
+{
+ Termcell *cells;
+
+ cells = ty->screen;
+ switch (mode)
+ {
+ case TERMPTY_CLR_END:
+ _termpty_clear_line(ty, mode, ty->w);
+ if (ty->state.cy < (ty->h - 1))
+ {
+ cells = &(ty->screen[(ty->state.cy + 1) * ty->w]);
+ _text_clear(ty, cells, ty->w * (ty->h - ty->state.cy - 1), 0, EINA_TRUE);
+ }
+ break;
+ case TERMPTY_CLR_BEGIN:
+ if (ty->state.cy > 0)
+ _text_clear(ty, cells, ty->w * ty->state.cy, 0, EINA_TRUE);
+ _termpty_clear_line(ty, mode, ty->w);
+ break;
+ case TERMPTY_CLR_ALL:
+ _text_clear(ty, cells, ty->w * ty->h, 0, EINA_TRUE);
+ break;
+ default:
+ break;
+ }
+ if (ty->cb.cancel_sel.func)
+ ty->cb.cancel_sel.func(ty->cb.cancel_sel.data);
+}
+
+void
+_termpty_clear_all(Termpty *ty)
+{
+ if (!ty->screen) return;
+ memset(ty->screen, 0, sizeof(*(ty->screen)) * ty->w * ty->h);
+}
+
+void
+_termpty_reset_att(Termatt *att)
+{
+ att->fg = COL_DEF;
+ att->bg = COL_DEF;
+ att->bold = 0;
+ att->faint = 0;
+#if defined(SUPPORT_ITALIC)
+ att->italic = 0;
+#elif defined(SUPPORT_DBLWIDTH)
+ att->dblwidth = 0;
+#endif
+ att->underline = 0;
+ att->blink = 0;
+ att->blink2 = 0;
+ att->inverse = 0;
+ att->invisible = 0;
+ att->strike = 0;
+ att->fg256 = 0;
+ att->bg256 = 0;
+ att->fgintense = 0;
+ att->bgintense = 0;
+ att->autowrapped = 0;
+ att->newline = 0;
+ att->tab = 0;
+}
+
+void
+_termpty_reset_state(Termpty *ty)
+{
+ ty->state.cx = 0;
+ ty->state.cy = 0;
+ ty->state.scroll_y1 = 0;
+ ty->state.scroll_y2 = 0;
+ ty->state.had_cr_x = 0;
+ ty->state.had_cr_y = 0;
+ _termpty_reset_att(&(ty->state.att));
+ ty->state.charset = 0;
+ ty->state.charsetch = 'B';
+ ty->state.chset[0] = 'B';
+ ty->state.chset[1] = 'B';
+ ty->state.chset[2] = 'B';
+ ty->state.chset[3] = 'B';
+ ty->state.multibyte = 0;
+ ty->state.alt_kp = 0;
+ ty->state.insert = 0;
+ ty->state.appcursor = 0;
+ ty->state.wrap = 1;
+ ty->state.wrapnext = 0;
+ ty->state.hidecursor = 0;
+ ty->state.crlf = 0;
+ ty->state.had_cr = 0;
+}
+
+void
+_termpty_cursor_copy(Termstate *state, Termstate *dest)
+{
+ dest->cx = state->cx;
+ dest->cy = state->cy;
+}
--- /dev/null
+typedef enum _Termpty_Clear
+{
+ TERMPTY_CLR_END,
+ TERMPTY_CLR_BEGIN,
+ TERMPTY_CLR_ALL
+} Termpty_Clear;
+
+void _termpty_text_copy(Termpty *ty, Termcell *cells, Termcell *dest, int count);
+void _termpty_text_scroll(Termpty *ty);
+void _termpty_text_scroll_rev(Termpty *ty);
+void _termpty_text_scroll_test(Termpty *ty);
+void _termpty_text_scroll_rev_test(Termpty *ty);
+void _termpty_text_append(Termpty *ty, const Eina_Unicode *codepoints, int len);
+void _termpty_clear_line(Termpty *ty, Termpty_Clear mode, int limit);
+void _termpty_clear_screen(Termpty *ty, Termpty_Clear mode);
+void _termpty_clear_all(Termpty *ty);
+void _termpty_reset_att(Termatt *att);
+void _termpty_reset_state(Termpty *ty);
+void _termpty_cursor_copy(Termstate *state, Termstate *dest);
+
+#define _term_txt_write(ty, txt) termpty_write(ty, txt, sizeof(txt) - 1)