Enable multiple arguments in SM and RM
[st.git] / st.c
diff --git a/st.c b/st.c
index d8acce4..f3f7f28 100644 (file)
--- a/st.c
+++ b/st.c
@@ -97,11 +97,11 @@ enum glyph_state {
 };
 
 enum term_mode {
-       MODE_WRAP        = 1,
+       MODE_WRAP       = 1,
        MODE_INSERT      = 2,
        MODE_APPKEYPAD   = 4,
        MODE_ALTSCREEN   = 8,
-       MODE_CRLF        = 16,
+       MODE_CRLF       = 16,
        MODE_MOUSEBTN    = 32,
        MODE_MOUSEMOTION = 64,
        MODE_MOUSE       = 32|64,
@@ -110,8 +110,8 @@ enum term_mode {
 
 enum escape_state {
        ESC_START      = 1,
-       ESC_CSI        = 2,
-       ESC_STR        = 4, /* DSC, OSC, PM, APC */
+       ESC_CSI = 2,
+       ESC_STR = 4, /* DSC, OSC, PM, APC */
        ESC_ALTCHARSET = 8,
        ESC_STR_END    = 16, /* a final string was encountered */
 };
@@ -152,21 +152,21 @@ typedef struct {
 /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
 typedef struct {
        char buf[ESC_BUF_SIZ]; /* raw string */
-       int len;               /* raw string length */
+       int len;               /* raw string length */
        char priv;
        int arg[ESC_ARG_SIZ];
-       int narg;              /* nb of args */
+       int narg;             /* nb of args */
        char mode;
 } CSIEscape;
 
 /* STR Escape sequence structs */
 /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
 typedef struct {
-       char type;             /* ESC type ... */
+       char type;           /* ESC type ... */
        char buf[STR_BUF_SIZ]; /* raw string */
-       int len;               /* raw string length */
+       int len;               /* raw string length */
        char *args[STR_ARG_SIZ];
-       int narg;              /* nb of args */
+       int narg;             /* nb of args */
 } STREscape;
 
 /* Internal representation of the screen */
@@ -262,7 +262,7 @@ static void tinsertblankline(int);
 static void tmoveto(int, int);
 static void tnew(int, int);
 static void tnewline(int);
-static void tputtab(void);
+static void tputtab(bool);
 static void tputc(char*);
 static void treset(void);
 static int tresize(int, int);
@@ -273,6 +273,7 @@ static void tsetchar(char*);
 static void tsetscroll(int, int);
 static void tswapscreen(void);
 static void tsetdirt(int, int);
+static void tsetmode(bool, bool, int *, int);
 static void tfulldirt(void);
 
 static void ttynew(void);
@@ -1178,6 +1179,79 @@ tsetscroll(int t, int b) {
        term.bot = b;
 }
 
+#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
+
+void
+tsetmode(bool priv, bool set, int *args, int narg) {
+       int *lim, mode;
+
+       for (lim = args + narg; args < lim; ++args) {
+               if(priv) {
+                       switch(*args) {
+                       case 1:
+                               MODBIT(term.mode, set, MODE_APPKEYPAD);
+                               break;
+                       case 5: /* DECSCNM -- Reverve video */
+                               mode = term.mode;
+                               MODBIT(term.mode,set, MODE_REVERSE);
+                               if (mode != term.mode)
+                                       draw();
+                               break;
+                       case 7:
+                               MODBIT(term.mode, set, MODE_WRAP);
+                               break;
+                       case 20:
+                               MODBIT(term.mode, set, MODE_CRLF);
+                               break;
+                       case 12: /* att610 -- Start blinking cursor (IGNORED) */
+                               break;
+                       case 25:
+                               MODBIT(term.c.state, !set, CURSOR_HIDE);
+                               break;
+                       case 1000: /* 1000,1002: enable xterm mouse report */
+                               MODBIT(term.mode, set, MODE_MOUSEBTN);
+                               break;
+                       case 1002:
+                               MODBIT(term.mode, set, MODE_MOUSEMOTION);
+                               break;
+                       case 1049: /* = 1047 and 1048 */
+                       case 47:
+                       case 1047:
+                               if(IS_SET(MODE_ALTSCREEN))
+                                       tclearregion(0, 0, term.col-1, term.row-1);
+                               if ((set && !IS_SET(MODE_ALTSCREEN)) ||
+                                   (!set && IS_SET(MODE_ALTSCREEN))) {
+                                           tswapscreen();
+                               }
+                               if (*args != 1049)
+                                       break;
+                               /* pass through */
+                       case 1048:
+                               tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
+                               break;
+                       default:
+                               fprintf(stderr,
+                                       "erresc: unknown private set/reset mode %d\n",
+                                       *args);
+                               break;
+                       }
+               } else {
+                       switch(*args) {
+                       case 4:
+                               MODBIT(term.mode, set, MODE_INSERT);
+                               break;
+                       default:
+                               fprintf(stderr,
+                                       "erresc: unknown set/reset mode %d\n",
+                                       *args);
+                               break;
+                       }
+               }
+       }
+}
+#undef MODBIT
+
+
 void
 csihandle(void) {
        switch(csiescseq.mode) {
@@ -1243,7 +1317,7 @@ csihandle(void) {
        case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
                DEFAULT(csiescseq.arg[0], 1);
                while (csiescseq.arg[0]--)
-                       tputtab();
+                       tputtab(1);
                break;
        case 'J': /* ED -- Clear screen */
                sel.bx = -1;
@@ -1291,58 +1365,7 @@ csihandle(void) {
                tinsertblankline(csiescseq.arg[0]);
                break;
        case 'l': /* RM -- Reset Mode */
-               if(csiescseq.priv) {
-                       switch(csiescseq.arg[0]) {
-                       case 1:
-                               term.mode &= ~MODE_APPKEYPAD;
-                               break;
-                       case 5: /* DECSCNM -- Remove reverse video */
-                               if(IS_SET(MODE_REVERSE)) {
-                                       term.mode &= ~MODE_REVERSE;
-                                       draw();
-                               }
-                               break;
-                       case 7:
-                               term.mode &= ~MODE_WRAP;
-                               break;
-                       case 12: /* att610 -- Stop blinking cursor (IGNORED) */
-                               break;
-                       case 20:
-                               term.mode &= ~MODE_CRLF;
-                               break;
-                       case 25:
-                               term.c.state |= CURSOR_HIDE;
-                               break;
-                       case 1000: /* disable X11 xterm mouse reporting */
-                               term.mode &= ~MODE_MOUSEBTN;
-                               break;
-                       case 1002:
-                               term.mode &= ~MODE_MOUSEMOTION;
-                               break;
-                       case 1049: /* = 1047 and 1048 */
-                       case 47:
-                       case 1047:
-                               if(IS_SET(MODE_ALTSCREEN)) {
-                                       tclearregion(0, 0, term.col-1, term.row-1);
-                                       tswapscreen();
-                               }
-                               if(csiescseq.arg[0] != 1049)
-                                       break;
-                       case 1048:
-                               tcursor(CURSOR_LOAD);
-                               break;
-                       default:
-                               goto unknown;
-                       }
-               } else {
-                       switch(csiescseq.arg[0]) {
-                       case 4:
-                               term.mode &= ~MODE_INSERT;
-                               break;
-                       default:
-                               goto unknown;
-                       }
-               }
+               tsetmode(csiescseq.priv, 0, csiescseq.arg, csiescseq.narg);
                break;
        case 'M': /* DL -- Delete <n> lines */
                DEFAULT(csiescseq.arg[0], 1);
@@ -1356,64 +1379,17 @@ csihandle(void) {
                DEFAULT(csiescseq.arg[0], 1);
                tdeletechar(csiescseq.arg[0]);
                break;
-       /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */
+       case 'Z': /* CBT -- Cursor Backward Tabulation <n> tab stops */
+               DEFAULT(csiescseq.arg[0], 1);
+               while (csiescseq.arg[0]--)
+                       tputtab(0);
+               break;
        case 'd': /* VPA -- Move to <row> */
                DEFAULT(csiescseq.arg[0], 1);
                tmoveto(term.c.x, csiescseq.arg[0]-1);
                break;
        case 'h': /* SM -- Set terminal mode */
-               if(csiescseq.priv) {
-                       switch(csiescseq.arg[0]) {
-                       case 1:
-                               term.mode |= MODE_APPKEYPAD;
-                               break;
-                       case 5: /* DECSCNM -- Reverve video */
-                               if(!IS_SET(MODE_REVERSE)) {
-                                       term.mode |= MODE_REVERSE;
-                                       draw();
-                               }
-                               break;
-                       case 7:
-                               term.mode |= MODE_WRAP;
-                               break;
-                       case 20:
-                               term.mode |= MODE_CRLF;
-                               break;
-                       case 12: /* att610 -- Start blinking cursor (IGNORED) */
-                                /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
-                               if(csiescseq.narg > 1 && csiescseq.arg[1] != 25)
-                                       break;
-                       case 25:
-                               term.c.state &= ~CURSOR_HIDE;
-                               break;
-                       case 1000: /* 1000,1002: enable xterm mouse report */
-                               term.mode |= MODE_MOUSEBTN;
-                               break;
-                       case 1002:
-                               term.mode |= MODE_MOUSEMOTION;
-                               break;
-                       case 1049: /* = 1047 and 1048 */
-                       case 47:
-                       case 1047:
-                               if(IS_SET(MODE_ALTSCREEN))
-                                       tclearregion(0, 0, term.col-1, term.row-1);
-                               else
-                                       tswapscreen();
-                               if(csiescseq.arg[0] != 1049)
-                                       break;
-                       case 1048:
-                               tcursor(CURSOR_SAVE);
-                               break;
-                       default: goto unknown;
-                       }
-               } else {
-                       switch(csiescseq.arg[0]) {
-                       case 4:
-                               term.mode |= MODE_INSERT;
-                               break;
-                       default: goto unknown;
-                       }
-               };
+               tsetmode(csiescseq.priv, 1, csiescseq.arg, csiescseq.narg);
                break;
        case 'm': /* SGR -- Terminal attribute (color) */
                tsetattr(csiescseq.arg, csiescseq.narg);
@@ -1461,22 +1437,24 @@ void
 strhandle(void) {
        char *p;
 
+       /*
+        * TODO: make this being useful in case of color palette change.
+        */
+       strparse();
+
        p = strescseq.buf; 
 
        switch(strescseq.type) {
        case ']': /* OSC -- Operating System Command */
                switch(p[0]) {
                case '0':
+               case '1':
                case '2':
                        /*
                         * TODO: Handle special chars in string, like umlauts.
                         */
                        if(p[1] == ';') {
-                               if(!strncmp(strescseq.buf, "settitle ", 9)) {
-                                       XStoreName(xw.dpy, xw.win, strescseq.buf+11);   
-                               } else {
-                                       XStoreName(xw.dpy, xw.win, strescseq.buf+2);
-                               }
+                               XStoreName(xw.dpy, xw.win, strescseq.buf+2);
                        }
                        break;
                case ';':
@@ -1531,11 +1509,20 @@ strreset(void) {
 }
 
 void
-tputtab(void) {
-       unsigned x;
+tputtab(bool forward) {
+       unsigned x = term.c.x;
 
-       for (x = term.c.x + 1; x < term.col && !term.tabs[x]; ++x)
-               /* nothing */ ;
+       if (forward) {
+               if (x == term.col)
+                       return;
+               for (++x; x < term.col && !term.tabs[x]; ++x)
+                       /* nothing */ ;
+       } else {
+               if (x == 0)
+                       return;
+               for (--x; x > 0 && !term.tabs[x]; --x)
+                       /* nothing */ ;
+       }
        tmoveto(x, term.c.y);
 }
 
@@ -1653,7 +1640,7 @@ tputc(char *c) {
                        sel.bx = -1;
                switch(ascii) {
                case '\t':
-                       tputtab();
+                       tputtab(1);
                        break;
                case '\b':
                        tmoveto(term.c.x-1, term.c.y);
@@ -1809,8 +1796,8 @@ void
 xclear(int x1, int y1, int x2, int y2) {
        XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? DefaultFG : DefaultBG]);
        XFillRectangle(xw.dpy, xw.buf, dc.gc,
-                      BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
-                      (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
+                      BORDER + x1 * xw.cw, BORDER + y1 * xw.ch,
+                      (x2-x1+1) * xw.cw, (y2-y1+1) * xw.ch);
 }
 
 void
@@ -1985,8 +1972,8 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) {
 /* copy buffer pixmap to screen pixmap */
 void
 xcopy() {
-        XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
-        XdbeSwapBuffers(xw.dpy, swpinfo, 1);
+       XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
+       XdbeSwapBuffers(xw.dpy, swpinfo, 1);
 
 }
 
@@ -2083,8 +2070,8 @@ expose(XEvent *ev) {
        if(xw.state & WIN_REDRAW) {
                if(!e->count)
                        xw.state &= ~WIN_REDRAW;
-        }
-        xcopy();
+       }
+       xcopy();
 }
 
 void