splut up termpty a lot. still escape handling is the largest bit -
authorraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 13 Jul 2012 08:46:33 +0000 (08:46 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 13 Jul 2012 08:46:33 +0000 (08:46 +0000)
1200 lines or so, but not a lot that canbe done about that as its the
smallest really logical unit there.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/terminology@73798 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/bin/Makefile.am
src/bin/termpty.c
src/bin/termpty.h
src/bin/termptyesc.c [new file with mode: 0644]
src/bin/termptyesc.h [new file with mode: 0644]
src/bin/termptyext.c [new file with mode: 0644]
src/bin/termptyext.h [new file with mode: 0644]
src/bin/termptygfx.c [new file with mode: 0644]
src/bin/termptygfx.h [new file with mode: 0644]
src/bin/termptyops.c [new file with mode: 0644]
src/bin/termptyops.h [new file with mode: 0644]

index dea6235..4f2f0f8 100644 (file)
@@ -27,6 +27,10 @@ options_wallpaper.c options_wallpaper.h \
 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
index 51ec2c9..d6ec000 100644 (file)
@@ -1,8 +1,8 @@
 #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>
@@ -12,7 +12,7 @@
 #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
@@ -45,1602 +45,6 @@ termpty_shutdown(void)
 }
 
 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;
@@ -1667,7 +71,7 @@ _handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
         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;
@@ -1703,7 +107,7 @@ _handle_buf(Termpty *ty, const Eina_Unicode *codepoints, int len)
      {
         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);
@@ -1826,7 +230,7 @@ termpty_new(const char *cmd, int w, int h, int backscroll)
    ty->h = h;
    ty->backmax = backscroll;
 
-   _reset_state(ty);
+   _termpty_reset_state(ty);
    ty->save = ty->state;
    ty->swap = ty->state;
 
@@ -2018,11 +422,11 @@ termpty_resize(Termpty *ty, int w, int h)
 
         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);
index 970a219..9582ef5 100644 (file)
@@ -132,3 +132,5 @@ Termcell *termpty_cellrow_get(Termpty *ty, int y, int *wret);
 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;
diff --git a/src/bin/termptyesc.c b/src/bin/termptyesc.c
new file mode 100644 (file)
index 0000000..0262470
--- /dev/null
@@ -0,0 +1,1224 @@
+#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;
+}
diff --git a/src/bin/termptyesc.h b/src/bin/termptyesc.h
new file mode 100644 (file)
index 0000000..c72cf55
--- /dev/null
@@ -0,0 +1,2 @@
+int _termpty_handle_seq(Termpty *ty, Eina_Unicode *c, Eina_Unicode *ce);
+    
diff --git a/src/bin/termptyext.c b/src/bin/termptyext.c
new file mode 100644 (file)
index 0000000..aef259a
--- /dev/null
@@ -0,0 +1,61 @@
+#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;
+}
diff --git a/src/bin/termptyext.h b/src/bin/termptyext.h
new file mode 100644 (file)
index 0000000..95bc894
--- /dev/null
@@ -0,0 +1,2 @@
+Eina_Bool _termpty_ext_handle(Termpty *ty, const char *txt, Eina_Unicode *utxt);
+    
diff --git a/src/bin/termptygfx.c b/src/bin/termptygfx.c
new file mode 100644 (file)
index 0000000..3a6a607
--- /dev/null
@@ -0,0 +1,53 @@
+#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;
+}
diff --git a/src/bin/termptygfx.h b/src/bin/termptygfx.h
new file mode 100644 (file)
index 0000000..e44efbd
--- /dev/null
@@ -0,0 +1,2 @@
+Eina_Unicode _termpty_charset_trans(Eina_Unicode g, int chset);
+    
diff --git a/src/bin/termptyops.c b/src/bin/termptyops.c
new file mode 100644 (file)
index 0000000..d7c2dbc
--- /dev/null
@@ -0,0 +1,354 @@
+#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;
+}
diff --git a/src/bin/termptyops.h b/src/bin/termptyops.h
new file mode 100644 (file)
index 0000000..bf93c6b
--- /dev/null
@@ -0,0 +1,21 @@
+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)