URI: 
       TERM set to xterm by default (which broke a lot of stuff), better escape handling (title), and a little clean up. - st - simple terminal
  HTML git clone https://git.parazyd.org/st
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit 0981437524b64579cc656f60b0108abdcdf8a0cd
   DIR parent f2dff29a16ef0eb1a0b680cdd753471ba406e4f5
  HTML Author: Aurélien Aptel <aurelien.aptel@gmail.com>
       Date:   Wed,  3 Feb 2010 03:25:35 +0100
       
       TERM set to xterm by default (which broke a lot of stuff), better escape handling (title), and a little clean up.
       
       Diffstat:
         M st.c                                |     389 +++++++++++++++----------------
       
       1 file changed, 190 insertions(+), 199 deletions(-)
       ---
   DIR diff --git a/st.c b/st.c
       @@ -20,11 +20,12 @@
        #include <X11/keysym.h>
        #include <X11/Xutil.h>
        
       -#define TNAME "st"
       +#define TNAME "xterm"
        
        /* Arbitrary sizes */
       +#define TITLESIZ 256
        #define ESCSIZ 256
       -#define ESCARG 16
       +#define ESCARGSIZ 16
        #define MAXDRAWBUF 1024
        
        #define SERRNO strerror(errno)
       @@ -40,7 +41,8 @@
        enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
        enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
        enum { CRset=1, CRupdate=2 };
       -enum { TMwrap=1, TMinsert=2 };
       +enum { TMwrap=1, TMinsert=2, TMtitle=4 };
       +enum { ESCin = 1, ESCcsi = 2, ESCosc = 4, ESCtitle = 8 };
        enum { SCupdate, SCredraw };
        
        typedef int Color;
       @@ -62,17 +64,16 @@ typedef struct {
                int y;
        } TCursor;
        
       -/* Escape sequence structs */
       -/* ESC <pre> [[ [<priv>] <arg> [;]] <mode>] */
       +/* CSI Escape sequence structs */
       +/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
        typedef struct {
       -        char buf[ESCSIZ+1]; /* raw string */
       +        char buf[ESCSIZ]; /* raw string */
                int len;            /* raw string length */
       -        char pre;           
                char priv;
       -        int arg[ESCARG+1];
       +        int arg[ESCARGSIZ];
                int narg;           /* nb of args */
                char mode;
       -} Escseq;
       +} CSIEscape;
        
        /* Internal representation of the screen */
        typedef struct {
       @@ -83,6 +84,9 @@ typedef struct {
                int top;    /* top    scroll limit */
                int bot;    /* bottom scroll limit */
                int mode;   /* terminal mode */
       +        int esc;
       +        char title[TITLESIZ];
       +        int titlelen;
        } Term;
        
        /* Purely graphic info */
       @@ -116,12 +120,10 @@ static void execsh(void);
        static void sigchld(int);
        static void run(void);
        
       -static int escaddc(char);
       -static int escfinal(char);
       -static void escdump(void);
       -static void eschandle(void);
       -static void escparse(void);
       -static void escreset(void);
       +static void csidump(void);
       +static void csihandle(void);
       +static void csiparse(void);
       +static void csireset(void);
        
        static void tclearregion(int, int, int, int);
        static void tcpos(int);
       @@ -168,7 +170,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
        static DC dc;
        static XWindow xw;
        static Term term;
       -static Escseq escseq;
       +static CSIEscape escseq;
        static int cmdfd;
        static pid_t pid;
        static int running;
       @@ -269,7 +271,7 @@ ttynew(void) {
        void
        dump(char c) {
                static int col;
       -        fprintf(stderr, " %02x %c ", c, isprint(c)?c:'.');
       +        fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
                if(++col % 10 == 0)
                        fprintf(stderr, "\n");
        }
       @@ -305,24 +307,6 @@ ttyresize(int x, int y) {
                        fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
        }
        
       -int
       -escfinal(char c) {
       -        if(escseq.len == 1)
       -                switch(c) {
       -                case '[':
       -                case ']':
       -                case '(':
       -                        return 0;
       -                case '=':
       -                case '>':
       -                default:
       -                        return 1;
       -                }
       -        else if(BETWEEN(c, 0x40, 0x7E))
       -                return 1;
       -        return 0;          
       -}
       -
        void
        tcpos(int mode) {
                static int x = 0;
       @@ -372,44 +356,27 @@ tnewline(void) {
                tmoveto(0, y);
        }
        
       -int
       -escaddc(char c) {
       -        escseq.buf[escseq.len++] = c;
       -        if(escfinal(c) || escseq.len >= ESCSIZ) {
       -                escparse(), eschandle();
       -                return 0;
       -        }
       -        return 1;
       -}
       -
        void
       -escparse(void) {
       +csiparse(void) {
                /* int noarg = 1; */
                char *p = escseq.buf;
        
                escseq.narg = 0;
       -        switch(escseq.pre = *p++) {
       -        case '[': /* CSI */
       -                if(*p == '?')
       -                        escseq.priv = 1, p++;
       -
       -                while(p < escseq.buf+escseq.len) {
       -                        while(isdigit(*p)) {
       -                                escseq.arg[escseq.narg] *= 10;
       -                                escseq.arg[escseq.narg] += *(p++) - '0'/*, noarg = 0 */;
       -                        }
       -                        if(*p == ';')
       -                                escseq.narg++, p++;
       -                        else {
       -                                escseq.mode = *p;
       -                                escseq.narg++;
       -                                return;
       -                        }
       +        if(*p == '?')
       +                escseq.priv = 1, p++;
       +        
       +        while(p < escseq.buf+escseq.len) {
       +                while(isdigit(*p)) {
       +                        escseq.arg[escseq.narg] *= 10;
       +                        escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
       +                }
       +                if(*p == ';' && escseq.narg+1 < ESCARGSIZ)
       +                        escseq.narg++, p++;
       +                else {
       +                        escseq.mode = *p;
       +                        escseq.narg++;
       +                        return;
                        }
       -                break;
       -        case '(':
       -                /* XXX: graphic character set */
       -                break;
                }
        }
        
       @@ -625,146 +592,141 @@ tsetscroll(int t, int b) {
        }
        
        void
       -eschandle(void) {
       -        switch(escseq.pre) {
       +csihandle(void) {
       +        switch(escseq.mode) {
                default:
       -                goto unknown_seq;
       -        case '[':
       -                switch(escseq.mode) {
       -                default:
       -                unknown_seq:
       -                        fprintf(stderr, "erresc: unknown sequence\n");
       -                        escdump();
       -                        break;
       -                case '@': /* Insert <n> blank char */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tinsertblank(escseq.arg[0]);
       -                        break;
       -                case 'A': /* Cursor <n> Up */
       -                case 'e':
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(term.c.x, term.c.y-escseq.arg[0]);
       -                        break;
       -                case 'B': /* Cursor <n> Down */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(term.c.x, term.c.y+escseq.arg[0]);
       -                        break;
       -                case 'C': /* Cursor <n> Forward */
       -                case 'a':
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(term.c.x+escseq.arg[0], term.c.y);
       -                        break;
       -                case 'D': /* Cursor <n> Backward */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(term.c.x-escseq.arg[0], term.c.y);
       -                        break;
       -                case 'E': /* Cursor <n> Down and first col */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(0, term.c.y+escseq.arg[0]);
       -                        break;
       -                case 'F': /* Cursor <n> Up and first col */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(0, term.c.y-escseq.arg[0]);
       -                        break;
       -                case 'G': /* Move to <col> */
       -                case '`':
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(escseq.arg[0]-1, term.c.y);
       +                fprintf(stderr, "erresc: unknown sequence\n");
       +                csidump();
       +                /* die(""); */
       +                break;
       +        case '@': /* Insert <n> blank char */
       +                DEFAULT(escseq.arg[0], 1);
       +                tinsertblank(escseq.arg[0]);
       +                break;
       +        case 'A': /* Cursor <n> Up */
       +        case 'e':
       +                DEFAULT(escseq.arg[0], 1);
       +                tmoveto(term.c.x, term.c.y-escseq.arg[0]);
       +                break;
       +        case 'B': /* Cursor <n> Down */
       +                DEFAULT(escseq.arg[0], 1);
       +                tmoveto(term.c.x, term.c.y+escseq.arg[0]);
       +                break;
       +        case 'C': /* Cursor <n> Forward */
       +        case 'a':
       +                DEFAULT(escseq.arg[0], 1);
       +                tmoveto(term.c.x+escseq.arg[0], term.c.y);
       +                break;
       +        case 'D': /* Cursor <n> Backward */
       +                DEFAULT(escseq.arg[0], 1);
       +                tmoveto(term.c.x-escseq.arg[0], term.c.y);
       +                break;
       +        case 'E': /* Cursor <n> Down and first col */
       +                DEFAULT(escseq.arg[0], 1);
       +                tmoveto(0, term.c.y+escseq.arg[0]);
       +                break;
       +        case 'F': /* Cursor <n> Up and first col */
       +                DEFAULT(escseq.arg[0], 1);
       +                tmoveto(0, term.c.y-escseq.arg[0]);
       +                break;
       +        case 'G': /* Move to <col> */
       +        case '`':
       +                DEFAULT(escseq.arg[0], 1);
       +             tmoveto(escseq.arg[0]-1, term.c.y);
       +                break;
       +        case 'H': /* Move to <row> <col> */
       +        case 'f':
       +                DEFAULT(escseq.arg[0], 1);
       +                DEFAULT(escseq.arg[1], 1);
       +                tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
       +                break;
       +        case 'J': /* Clear screen */
       +                switch(escseq.arg[0]) {
       +                case 0: /* below */
       +                        tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
                                break;
       -                case 'H': /* Move to <row> <col> */
       -                case 'f':
       -                        DEFAULT(escseq.arg[0], 1);
       -                        DEFAULT(escseq.arg[1], 1);
       -                        tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
       +                case 1: /* above */
       +                        tclearregion(0, 0, term.c.x, term.c.y);
                                break;
       -                case 'J': /* Clear screen */
       -                        switch(escseq.arg[0]) {
       -                        case 0: /* below */
       -                                tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
       -                                break;
       -                        case 1: /* above */
       -                                tclearregion(0, 0, term.c.x, term.c.y);
       -                                break;
       -                        case 2: /* all */
       -                                tclearregion(0, 0, term.col-1, term.row-1);
       -                                break;                                  
       -                        }
       +                case 2: /* all */
       +                        tclearregion(0, 0, term.col-1, term.row-1);
       +                        break;                                  
       +                }
       +                break;
       +        case 'K': /* Clear line */
       +                switch(escseq.arg[0]) {
       +                case 0: /* right */
       +                        tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
                                break;
       -                case 'K': /* Clear line */
       -                        switch(escseq.arg[0]) {
       -                        case 0: /* right */
       -                                tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
       -                                break;
       -                        case 1: /* left */
       -                                tclearregion(0, term.c.y, term.c.x, term.c.y);
       -                                break;
       -                        case 2: /* all */
       -                                tclearregion(0, term.c.y, term.col-1, term.c.y);
       -                                break;
       -                        }
       +                case 1: /* left */
       +                        tclearregion(0, term.c.y, term.c.x, term.c.y);
                                break;
       -                case 'L': /* Insert <n> blank lines */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tinsertblankline(escseq.arg[0]);
       +                case 2: /* all */
       +                        tclearregion(0, term.c.y, term.col-1, term.c.y);
                                break;
       -                case 'l':
       -                        if(escseq.priv && escseq.arg[0] == 25)
       +                }
       +                break;
       +        case 'S':
       +        case 'L': /* Insert <n> blank lines */
       +                DEFAULT(escseq.arg[0], 1);
       +                tinsertblankline(escseq.arg[0]);
       +                break;
       +        case 'l':
       +                if(escseq.priv && escseq.arg[0] == 25)
                                        term.c.hidden = 1;
       -                        break;
       -                case 'M': /* Delete <n> lines */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tdeleteline(escseq.arg[0]);
       -                        break;
       -                case 'P': /* Delete <n> char */
       -                        DEFAULT(escseq.arg[0], 1);
       -                        tdeletechar(escseq.arg[0]);
       -                        break;
       -                case 'd': /* Move to <row> */
       +                break;
       +        case 'M': /* Delete <n> lines */
       +                DEFAULT(escseq.arg[0], 1);
       +                tdeleteline(escseq.arg[0]);
       +                break;
       +        case 'X':
       +        case 'P': /* Delete <n> char */
       +                DEFAULT(escseq.arg[0], 1);
       +                tdeletechar(escseq.arg[0]);
       +                break;
       +        case 'd': /* Move to <row> */
       +                DEFAULT(escseq.arg[0], 1);
       +                tmoveto(term.c.x, escseq.arg[0]-1);
       +                break;
       +        case 'h': /* Set terminal mode */
       +                if(escseq.priv && escseq.arg[0] == 25)
       +                        term.c.hidden = 0;
       +                break;
       +        case 'm': /* Terminal attribute (color) */
       +                tsetattr(escseq.arg, escseq.narg);
       +                break;
       +        case 'r':
       +                if(escseq.priv)
       +                        ;
       +                else {
                                DEFAULT(escseq.arg[0], 1);
       -                        tmoveto(term.c.x, escseq.arg[0]-1);
       -                        break;
       -                case 'h': /* Set terminal mode */
       -                        if(escseq.priv && escseq.arg[0] == 25)
       -                                term.c.hidden = 0;
       -                        break;
       -                case 'm': /* Terminal attribute (color) */
       -                        tsetattr(escseq.arg, escseq.narg);
       -                        break;
       -                case 'r':
       -                        if(escseq.priv)
       -                                ;
       -                        else {
       -                                DEFAULT(escseq.arg[0], 1);
       -                                DEFAULT(escseq.arg[1], term.row);
       -                                tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
       -                        }
       -                        break;
       -                case 's': /* Save cursor position */
       -                        tcpos(CSsave);
       -                        break;
       -                case 'u': /* Load cursor position */
       -                        tcpos(CSload);
       -                        break;
       +                        DEFAULT(escseq.arg[1], term.row);
       +                        tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
                        }
                        break;
       +        case 's': /* Save cursor position */
       +                tcpos(CSsave);
       +                break;
       +        case 'u': /* Load cursor position */
       +                tcpos(CSload);
       +                break;
                }
        }
        
        void
       -escdump(void) { 
       +csidump(void) { 
                int i;
       -        printf("rawbuf        : %s\n", escseq.buf);
       -        printf("prechar : %c\n", escseq.pre);
       -        printf("private : %c\n", escseq.priv ? '?' : ' ');
       -        printf("narg        : %d\n", escseq.narg);
       +        printf("ESC [ %s", escseq.priv ? "? " : "");
                if(escseq.narg)
                        for(i = 0; i < escseq.narg; i++)
       -                        printf("\targ %d = %d\n", i, escseq.arg[i]);
       -        printf("mode        : %c\n", escseq.mode);
       +                        printf("%d ", escseq.arg[i]);
       +        if(escseq.mode)
       +                putchar(escseq.mode);
       +        putchar('\n');
        }
        
        void
       -escreset(void) {
       +csireset(void) {
                memset(&escseq, 0, sizeof(escseq));
        }
        
       @@ -781,21 +743,41 @@ tputtab(void) {
        
        void
        tputc(char c) {
       -        static int inesc = 0;
        #if 0
                dump(c);
        #endif        
       -        /* start of escseq */
       -        if(c == '\033')
       -                escreset(), inesc = 1;
       -        else if(inesc) {
       -                inesc = escaddc(c);
       -        } /* normal char */ 
       -        else switch(c) { 
       -                default:
       -                        tsetchar(c);
       -                        tcursor(CSright);
       -                        break;
       +        if(term.esc & ESCin) {
       +                if(term.esc & ESCcsi) {
       +                        escseq.buf[escseq.len++] = c;
       +                        if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) {
       +                                term.esc = 0;
       +                                csiparse(), csihandle();
       +                        }
       +                } else if (term.esc & ESCosc) {
       +                        if(c == ';') {
       +                                term.titlelen = 0;
       +                                term.esc = ESCin | ESCtitle;
       +                        }
       +                } else if(term.esc & ESCtitle) {
       +                        if(c == '\a' || term.titlelen+1 >= TITLESIZ) {
       +                                term.esc = 0;
       +                                term.title[term.titlelen] = '\0';
       +                                XStoreName(xw.dis, xw.win, term.title);
       +                        } else {
       +                                term.title[term.titlelen++] = c;
       +                        }
       +                } else {                
       +                        switch(c) {
       +                        case '[':
       +                                term.esc |= ESCcsi;
       +                                break;
       +                        case ']':
       +                                term.esc |= ESCosc;
       +                                break;
       +                        }
       +                }
       +        } else {
       +                switch(c) {
                        case '\t':
                                tputtab();
                                break;
       @@ -811,6 +793,15 @@ tputc(char c) {
                        case '\a':
                                xbell();
                                break;
       +                case '\033':
       +                        csireset();
       +                        term.esc = ESCin;
       +                        break;
       +                default:
       +                        tsetchar(c);
       +                        tcursor(CSright);
       +                        break;
       +                }
                }
        }