Add OSC, DSC, PM, APC and settitle. - st - Personal fork of st
 (HTM) git clone git://git.drkhsh.at/st.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 6696ef8563a58ee07e4de5b3a74b52b91934f6a9
 (DIR) parent ff040e9894f62fe28bf100488211d0a407740668
 (HTM) Author: Christoph Lohmann <20h@r-36.net>
       Date:   Wed, 29 Aug 2012 23:14:20 +0200
       
       Add OSC, DSC, PM, APC and settitle.
       
       Diffstat:
         M TODO                                |       1 +
         M st.c                                |     279 +++++++++++++++++++++----------
       
       2 files changed, 191 insertions(+), 89 deletions(-)
       ---
 (DIR) diff --git a/TODO b/TODO
       @@ -20,6 +20,7 @@ bugs
        * fix shift up/down (shift selection in emacs)
        * fix selection click
        * fix selection paste for xatom STRING
       +* fix umlaut handling in settitle
        
        misc
        ----
 (DIR) diff --git a/st.c b/st.c
       @@ -43,9 +43,10 @@
        #define XEMBED_FOCUS_OUT 5
        
        /* Arbitrary sizes */
       -#define ESC_TITLE_SIZ 256
        #define ESC_BUF_SIZ   256
        #define ESC_ARG_SIZ   16
       +#define STR_BUF_SIZ   256
       +#define STR_ARG_SIZ   16
        #define DRAW_BUF_SIZ  1024
        #define UTF_SIZ       4
        #define XK_NO_MOD     UINT_MAX
       @@ -110,9 +111,9 @@ enum term_mode {
        enum escape_state {
                ESC_START      = 1,
                ESC_CSI        = 2,
       -        ESC_OSC        = 4,
       -        ESC_TITLE      = 8,
       -        ESC_ALTCHARSET = 16
       +        ESC_STR        = 4, /* DSC, OSC, PM, APC */
       +        ESC_ALTCHARSET = 8,
       +        ESC_STR_END    = 16, /* a final string was encountered */
        };
        
        enum window_state {
       @@ -158,6 +159,16 @@ typedef struct {
                char mode;
        } CSIEscape;
        
       +/* STR Escape sequence structs */
       +/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
       +typedef struct {
       +        char type;             /* ESC type ... */
       +        char buf[STR_BUF_SIZ]; /* raw string */
       +        int len;               /* raw string length */
       +        char *args[STR_ARG_SIZ];
       +        int narg;              /* nb of args */
       +} STREscape;
       +
        /* Internal representation of the screen */
        typedef struct {
                int row;        /* nb row */
       @@ -170,8 +181,6 @@ typedef struct {
                int bot;        /* bottom scroll limit */
                int mode;        /* terminal mode flags */
                int esc;        /* escape state flags */
       -        char title[ESC_TITLE_SIZ];
       -        int titlelen;
                bool *tabs;
        } Term;
        
       @@ -239,6 +248,10 @@ static void csidump(void);
        static void csihandle(void);
        static void csiparse(void);
        static void csireset(void);
       +static void strdump(void);
       +static void strhandle(void);
       +static void strparse(void);
       +static void strreset(void);
        
        static void tclearregion(int, int, int, int);
        static void tcursor(int);
       @@ -323,7 +336,8 @@ static void (*handler[LASTEvent])(XEvent *) = {
        static DC dc;
        static XWindow xw;
        static Term term;
       -static CSIEscape escseq;
       +static CSIEscape csiescseq;
       +static STREscape strescseq;
        static int cmdfd;
        static pid_t pid;
        static Selection sel;
       @@ -968,22 +982,22 @@ tnewline(int first_col) {
        void
        csiparse(void) {
                /* int noarg = 1; */
       -        char *p = escseq.buf;
       +        char *p = csiescseq.buf;
        
       -        escseq.narg = 0;
       +        csiescseq.narg = 0;
                if(*p == '?')
       -                escseq.priv = 1, p++;
       +                csiescseq.priv = 1, p++;
                
       -        while(p < escseq.buf+escseq.len) {
       +        while(p < csiescseq.buf+csiescseq.len) {
                        while(isdigit(*p)) {
       -                        escseq.arg[escseq.narg] *= 10;
       -                        escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
       +                        csiescseq.arg[csiescseq.narg] *= 10;
       +                        csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg = 0 */;
                        }
       -                if(*p == ';' && escseq.narg+1 < ESC_ARG_SIZ)
       -                        escseq.narg++, p++;
       +                if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ)
       +                        csiescseq.narg++, p++;
                        else {
       -                        escseq.mode = *p;
       -                        escseq.narg++;
       +                        csiescseq.mode = *p;
       +                        csiescseq.narg++;
                                return;
                        }
                }
       @@ -1166,7 +1180,7 @@ tsetscroll(int t, int b) {
        
        void
        csihandle(void) {
       -        switch(escseq.mode) {
       +        switch(csiescseq.mode) {
                default:
                unknown:
                        fprintf(stderr, "erresc: unknown csi ");
       @@ -1174,37 +1188,37 @@ csihandle(void) {
                        /* die(""); */
                        break;
                case '@': /* ICH -- Insert <n> blank char */
       -                DEFAULT(escseq.arg[0], 1);
       -                tinsertblank(escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tinsertblank(csiescseq.arg[0]);
                        break;
                case 'A': /* CUU -- Cursor <n> Up */
                case 'e':
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(term.c.x, term.c.y-escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(term.c.x, term.c.y-csiescseq.arg[0]);
                        break;
                case 'B': /* CUD -- Cursor <n> Down */
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(term.c.x, term.c.y+escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(term.c.x, term.c.y+csiescseq.arg[0]);
                        break;
                case 'C': /* CUF -- Cursor <n> Forward */
                case 'a':
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(term.c.x+escseq.arg[0], term.c.y);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(term.c.x+csiescseq.arg[0], term.c.y);
                        break;
                case 'D': /* CUB -- Cursor <n> Backward */
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(term.c.x-escseq.arg[0], term.c.y);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(term.c.x-csiescseq.arg[0], term.c.y);
                        break;
                case 'E': /* CNL -- Cursor <n> Down and first col */
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(0, term.c.y+escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(0, term.c.y+csiescseq.arg[0]);
                        break;
                case 'F': /* CPL -- Cursor <n> Up and first col */
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(0, term.c.y-escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(0, term.c.y-csiescseq.arg[0]);
                        break;
                case 'g': /* TBC -- Tabulation clear */
       -                switch (escseq.arg[0]) {
       +                switch (csiescseq.arg[0]) {
                        case 0: /* clear current tab stop */
                                term.tabs[term.c.x] = 0;
                                break;
       @@ -1217,23 +1231,23 @@ csihandle(void) {
                        break;
                case 'G': /* CHA -- Move to <col> */
                case '`': /* XXX: HPA -- same? */
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(escseq.arg[0]-1, term.c.y);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(csiescseq.arg[0]-1, term.c.y);
                        break;
                case 'H': /* CUP -- Move to <row> <col> */
                case 'f': /* XXX: HVP -- same? */
       -                DEFAULT(escseq.arg[0], 1);
       -                DEFAULT(escseq.arg[1], 1);
       -                tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                DEFAULT(csiescseq.arg[1], 1);
       +                tmoveto(csiescseq.arg[1]-1, csiescseq.arg[0]-1);
                        break;
                case 'I': /* CHT -- Cursor Forward Tabulation <n> tab stops */
       -                DEFAULT(escseq.arg[0], 1);
       -                while (escseq.arg[0]--)
       +                DEFAULT(csiescseq.arg[0], 1);
       +                while (csiescseq.arg[0]--)
                                tputtab();
                        break;
                case 'J': /* ED -- Clear screen */
                        sel.bx = -1;
       -                switch(escseq.arg[0]) {
       +                switch(csiescseq.arg[0]) {
                        case 0: /* below */
                                tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
                                if(term.c.y < term.row-1)
       @@ -1252,7 +1266,7 @@ csihandle(void) {
                        }
                        break;
                case 'K': /* EL -- Clear line */
       -                switch(escseq.arg[0]) {
       +                switch(csiescseq.arg[0]) {
                        case 0: /* right */
                                tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
                                break;
       @@ -1265,20 +1279,20 @@ csihandle(void) {
                        }
                        break;
                case 'S': /* SU -- Scroll <n> line up */
       -                DEFAULT(escseq.arg[0], 1);
       -                tscrollup(term.top, escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tscrollup(term.top, csiescseq.arg[0]);
                        break;
                case 'T': /* SD -- Scroll <n> line down */
       -                DEFAULT(escseq.arg[0], 1);
       -                tscrolldown(term.top, escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tscrolldown(term.top, csiescseq.arg[0]);
                        break;
                case 'L': /* IL -- Insert <n> blank lines */
       -                DEFAULT(escseq.arg[0], 1);
       -                tinsertblankline(escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tinsertblankline(csiescseq.arg[0]);
                        break;
                case 'l': /* RM -- Reset Mode */
       -                if(escseq.priv) {
       -                        switch(escseq.arg[0]) {
       +                if(csiescseq.priv) {
       +                        switch(csiescseq.arg[0]) {
                                case 1:
                                        term.mode &= ~MODE_APPKEYPAD;
                                        break;
       @@ -1312,7 +1326,7 @@ csihandle(void) {
                                                tclearregion(0, 0, term.col-1, term.row-1);
                                                tswapscreen();
                                        }
       -                                if(escseq.arg[0] != 1049)
       +                                if(csiescseq.arg[0] != 1049)
                                                break;
                                case 1048:
                                        tcursor(CURSOR_LOAD);
       @@ -1321,7 +1335,7 @@ csihandle(void) {
                                        goto unknown;
                                }
                        } else {
       -                        switch(escseq.arg[0]) {
       +                        switch(csiescseq.arg[0]) {
                                case 4:
                                        term.mode &= ~MODE_INSERT;
                                        break;
       @@ -1331,25 +1345,25 @@ csihandle(void) {
                        }
                        break;
                case 'M': /* DL -- Delete <n> lines */
       -                DEFAULT(escseq.arg[0], 1);
       -                tdeleteline(escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tdeleteline(csiescseq.arg[0]);
                        break;
                case 'X': /* ECH -- Erase <n> char */
       -                DEFAULT(escseq.arg[0], 1);
       -                tclearregion(term.c.x, term.c.y, term.c.x + escseq.arg[0], term.c.y);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tclearregion(term.c.x, term.c.y, term.c.x + csiescseq.arg[0], term.c.y);
                        break;
                case 'P': /* DCH -- Delete <n> char */
       -                DEFAULT(escseq.arg[0], 1);
       -                tdeletechar(escseq.arg[0]);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tdeletechar(csiescseq.arg[0]);
                        break;
                /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */
                case 'd': /* VPA -- Move to <row> */
       -                DEFAULT(escseq.arg[0], 1);
       -                tmoveto(term.c.x, escseq.arg[0]-1);
       +                DEFAULT(csiescseq.arg[0], 1);
       +                tmoveto(term.c.x, csiescseq.arg[0]-1);
                        break;
                case 'h': /* SM -- Set terminal mode */
       -                if(escseq.priv) {
       -                        switch(escseq.arg[0]) {
       +                if(csiescseq.priv) {
       +                        switch(csiescseq.arg[0]) {
                                case 1:
                                        term.mode |= MODE_APPKEYPAD;
                                        break;
       @@ -1367,7 +1381,7 @@ csihandle(void) {
                                        break;
                                case 12: /* att610 -- Start blinking cursor (IGNORED) */
                                         /* fallthrough for xterm cvvis = CSI [ ? 12 ; 25 h */
       -                                if(escseq.narg > 1 && escseq.arg[1] != 25)
       +                                if(csiescseq.narg > 1 && csiescseq.arg[1] != 25)
                                                break;
                                case 25:
                                        term.c.state &= ~CURSOR_HIDE;
       @@ -1385,7 +1399,7 @@ csihandle(void) {
                                                tclearregion(0, 0, term.col-1, term.row-1);
                                        else
                                                tswapscreen();
       -                                if(escseq.arg[0] != 1049)
       +                                if(csiescseq.arg[0] != 1049)
                                                break;
                                case 1048:
                                        tcursor(CURSOR_SAVE);
       @@ -1393,7 +1407,7 @@ csihandle(void) {
                                default: goto unknown;
                                }
                        } else {
       -                        switch(escseq.arg[0]) {
       +                        switch(csiescseq.arg[0]) {
                                case 4:
                                        term.mode |= MODE_INSERT;
                                        break;
       @@ -1402,15 +1416,15 @@ csihandle(void) {
                        };
                        break;
                case 'm': /* SGR -- Terminal attribute (color) */
       -                tsetattr(escseq.arg, escseq.narg);
       +                tsetattr(csiescseq.arg, csiescseq.narg);
                        break;
                case 'r': /* DECSTBM -- Set Scrolling Region */
       -                if(escseq.priv)
       +                if(csiescseq.priv)
                                goto unknown;
                        else {
       -                        DEFAULT(escseq.arg[0], 1);
       -                        DEFAULT(escseq.arg[1], term.row);
       -                        tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
       +                        DEFAULT(csiescseq.arg[0], 1);
       +                        DEFAULT(csiescseq.arg[1], term.row);
       +                        tsetscroll(csiescseq.arg[0]-1, csiescseq.arg[1]-1);
                                tmoveto(0, 0);
                        }
                        break;
       @@ -1427,8 +1441,8 @@ void
        csidump(void) {
                int i;
                printf("ESC[");
       -        for(i = 0; i < escseq.len; i++) {
       -                uint c = escseq.buf[i] & 0xff;
       +        for(i = 0; i < csiescseq.len; i++) {
       +                uint c = csiescseq.buf[i] & 0xff;
                        if(isprint(c)) putchar(c);
                        else if(c == '\n') printf("(\\n)");
                        else if(c == '\r') printf("(\\r)");
       @@ -1440,7 +1454,80 @@ csidump(void) {
        
        void
        csireset(void) {
       -        memset(&escseq, 0, sizeof(escseq));
       +        memset(&csiescseq, 0, sizeof(csiescseq));
       +}
       +
       +void
       +strhandle(void) {
       +        char *p;
       +
       +        p = strescseq.buf; 
       +
       +        switch(strescseq.type) {
       +        case ']': /* OSC -- Operating System Command */
       +                switch(p[0]) {
       +                case '0':
       +                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);
       +                                }
       +                        }
       +                        break;
       +                case ';':
       +                        XStoreName(xw.dpy, xw.win, strescseq.buf+1);
       +                        break;
       +                case '4': /* TODO: Set color (arg0) to "rgb:%hexr/$hexg/$hexb" (arg1) */
       +                        break;
       +                default:
       +                        fprintf(stderr, "erresc: unknown str ");
       +                        strdump();
       +                        break;
       +                }
       +                break;
       +        case 'P': /* DSC -- Device Control String */
       +        case '_': /* APC -- Application Program Command */
       +        case '^': /* PM -- Privacy Message */
       +        default:
       +                fprintf(stderr, "erresc: unknown str ");
       +                strdump();
       +                /* die(""); */
       +                break;
       +        }
       +}
       +
       +void
       +strparse(void) {
       +        /*
       +         * TODO: Implement parsing like for CSI when required.
       +         * Format: ESC type cmd ';' arg0 [';' argn] ESC \
       +         */
       +        return;
       +}
       +
       +void
       +strdump(void) {
       +        int i;
       +        printf("ESC%c", strescseq.type);
       +        for(i = 0; i < strescseq.len; i++) {
       +                uint c = strescseq.buf[i] & 0xff;
       +                if(isprint(c)) putchar(c);
       +                else if(c == '\n') printf("(\\n)");
       +                else if(c == '\r') printf("(\\r)");
       +                else if(c == 0x1b) printf("(\\e)");
       +                else printf("(%02x)", c);
       +        }
       +        printf("ESC\\\n");
       +}
       +
       +void
       +strreset(void) {
       +        memset(&strescseq, 0, sizeof(strescseq));
        }
        
        void
       @@ -1457,25 +1544,31 @@ tputc(char *c) {
                char ascii = *c;
                if(term.esc & ESC_START) {
                        if(term.esc & ESC_CSI) {
       -                        escseq.buf[escseq.len++] = ascii;
       -                        if(BETWEEN(ascii, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) {
       +                        csiescseq.buf[csiescseq.len++] = ascii;
       +                        if(BETWEEN(ascii, 0x40, 0x7E) || csiescseq.len >= ESC_BUF_SIZ) {
                                        term.esc = 0;
                                        csiparse(), csihandle();
                                }
       -                        /* TODO: handle other OSC */
       -                } else if(term.esc & ESC_OSC) {
       -                        if(ascii == ';') {
       -                                term.titlelen = 0;
       -                                term.esc = ESC_START | ESC_TITLE;
       -                        }
       -                } else if(term.esc & ESC_TITLE) {
       -                        if(ascii == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) {
       +                } else if(term.esc & ESC_STR) {
       +                        switch(ascii) {
       +                        case '\033':
       +                                term.esc = ESC_START | ESC_STR_END;
       +                                break;
       +                        case '\a': /* backwards compatibility to xterm */
                                        term.esc = 0;
       -                                term.title[term.titlelen] = '\0';
       -                                XStoreName(xw.dpy, xw.win, term.title);
       -                        } else {
       -                                term.title[term.titlelen++] = ascii;
       +                                strhandle();
       +                                break;
       +                        default:
       +                                strescseq.buf[strescseq.len++] = ascii;
       +                                if (strescseq.len+1 >= STR_BUF_SIZ) {
       +                                        term.esc = 0;
       +                                        strhandle();
       +                                }
                                }
       +                } else if(term.esc & ESC_STR_END) {
       +                        term.esc = 0;
       +                        if(ascii == '\\')
       +                                strhandle();
                        } else if(term.esc & ESC_ALTCHARSET) {
                                switch(ascii) {
                                case '0': /* Line drawing crap */
       @@ -1493,8 +1586,13 @@ tputc(char *c) {
                                case '[':
                                        term.esc |= ESC_CSI;
                                        break;
       -                        case ']':
       -                                term.esc |= ESC_OSC;
       +                        case 'P': /* DCS -- Device Control String */
       +                        case '_': /* APC -- Application Program Command */
       +                        case '^': /* PM -- Privacy Message */
       +                        case ']': /* OSC -- Operating System Command */
       +                                strreset();
       +                                strescseq.type = ascii;
       +                                term.esc |= ESC_STR;
                                        break;
                                case '(':
                                        term.esc |= ESC_ALTCHARSET;
       @@ -1541,6 +1639,9 @@ tputc(char *c) {
                                        tcursor(CURSOR_LOAD);
                                        term.esc = 0;
                                        break;
       +                        case '\\': /* ST -- Stop */
       +                                term.esc = 0;
       +                                break;
                                default:
                                        fprintf(stderr, "erresc: unknown sequence ESC 0x%02X '%c'\n",
                                            (uchar) ascii, isprint(ascii)?ascii:'.');