TERM set to xterm by default (which broke a lot of stuff), better escape handling (title), and a little clean up.

This commit is contained in:
Aurélien Aptel 2010-02-03 03:25:35 +01:00
parent f2dff29a16
commit 0981437524

395
st.c
View File

@ -20,11 +20,12 @@
#include <X11/keysym.h> #include <X11/keysym.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#define TNAME "st" #define TNAME "xterm"
/* Arbitrary sizes */ /* Arbitrary sizes */
#define TITLESIZ 256
#define ESCSIZ 256 #define ESCSIZ 256
#define ESCARG 16 #define ESCARGSIZ 16
#define MAXDRAWBUF 1024 #define MAXDRAWBUF 1024
#define SERRNO strerror(errno) #define SERRNO strerror(errno)
@ -40,7 +41,8 @@
enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 }; enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload }; enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
enum { CRset=1, CRupdate=2 }; 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 }; enum { SCupdate, SCredraw };
typedef int Color; typedef int Color;
@ -62,17 +64,16 @@ typedef struct {
int y; int y;
} TCursor; } TCursor;
/* Escape sequence structs */ /* CSI Escape sequence structs */
/* ESC <pre> [[ [<priv>] <arg> [;]] <mode>] */ /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
typedef struct { typedef struct {
char buf[ESCSIZ+1]; /* raw string */ char buf[ESCSIZ]; /* raw string */
int len; /* raw string length */ int len; /* raw string length */
char pre;
char priv; char priv;
int arg[ESCARG+1]; int arg[ESCARGSIZ];
int narg; /* nb of args */ int narg; /* nb of args */
char mode; char mode;
} Escseq; } CSIEscape;
/* Internal representation of the screen */ /* Internal representation of the screen */
typedef struct { typedef struct {
@ -83,6 +84,9 @@ typedef struct {
int top; /* top scroll limit */ int top; /* top scroll limit */
int bot; /* bottom scroll limit */ int bot; /* bottom scroll limit */
int mode; /* terminal mode */ int mode; /* terminal mode */
int esc;
char title[TITLESIZ];
int titlelen;
} Term; } Term;
/* Purely graphic info */ /* Purely graphic info */
@ -116,12 +120,10 @@ static void execsh(void);
static void sigchld(int); static void sigchld(int);
static void run(void); static void run(void);
static int escaddc(char); static void csidump(void);
static int escfinal(char); static void csihandle(void);
static void escdump(void); static void csiparse(void);
static void eschandle(void); static void csireset(void);
static void escparse(void);
static void escreset(void);
static void tclearregion(int, int, int, int); static void tclearregion(int, int, int, int);
static void tcpos(int); static void tcpos(int);
@ -168,7 +170,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
static DC dc; static DC dc;
static XWindow xw; static XWindow xw;
static Term term; static Term term;
static Escseq escseq; static CSIEscape escseq;
static int cmdfd; static int cmdfd;
static pid_t pid; static pid_t pid;
static int running; static int running;
@ -269,7 +271,7 @@ ttynew(void) {
void void
dump(char c) { dump(char c) {
static int col; static int col;
fprintf(stderr, " %02x %c ", c, isprint(c)?c:'.'); fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
if(++col % 10 == 0) if(++col % 10 == 0)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
@ -305,24 +307,6 @@ ttyresize(int x, int y) {
fprintf(stderr, "Couldn't set window size: %s\n", SERRNO); 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 void
tcpos(int mode) { tcpos(int mode) {
static int x = 0; static int x = 0;
@ -372,44 +356,27 @@ tnewline(void) {
tmoveto(0, y); 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 void
escparse(void) { csiparse(void) {
/* int noarg = 1; */ /* int noarg = 1; */
char *p = escseq.buf; char *p = escseq.buf;
escseq.narg = 0; escseq.narg = 0;
switch(escseq.pre = *p++) { if(*p == '?')
case '[': /* CSI */ escseq.priv = 1, p++;
if(*p == '?')
escseq.priv = 1, p++;
while(p < escseq.buf+escseq.len) { while(p < escseq.buf+escseq.len) {
while(isdigit(*p)) { while(isdigit(*p)) {
escseq.arg[escseq.narg] *= 10; escseq.arg[escseq.narg] *= 10;
escseq.arg[escseq.narg] += *(p++) - '0'/*, noarg = 0 */; escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
} }
if(*p == ';') if(*p == ';' && escseq.narg+1 < ESCARGSIZ)
escseq.narg++, p++; escseq.narg++, p++;
else { else {
escseq.mode = *p; escseq.mode = *p;
escseq.narg++; escseq.narg++;
return; return;
}
} }
break;
case '(':
/* XXX: graphic character set */
break;
} }
} }
@ -625,146 +592,141 @@ tsetscroll(int t, int b) {
} }
void void
eschandle(void) { csihandle(void) {
switch(escseq.pre) { switch(escseq.mode) {
default: default:
goto unknown_seq; fprintf(stderr, "erresc: unknown sequence\n");
case '[': csidump();
switch(escseq.mode) { /* die(""); */
default: break;
unknown_seq: case '@': /* Insert <n> blank char */
fprintf(stderr, "erresc: unknown sequence\n"); DEFAULT(escseq.arg[0], 1);
escdump(); 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; break;
case '@': /* Insert <n> blank char */ case 1: /* above */
DEFAULT(escseq.arg[0], 1); tclearregion(0, 0, term.c.x, term.c.y);
tinsertblank(escseq.arg[0]);
break; break;
case 'A': /* Cursor <n> Up */ case 2: /* all */
case 'e': tclearregion(0, 0, term.col-1, term.row-1);
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 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;
}
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;
}
break;
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> */
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; break;
} }
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 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;
}
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 '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);
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 void
escdump(void) { csidump(void) {
int i; int i;
printf("rawbuf : %s\n", escseq.buf); printf("ESC [ %s", escseq.priv ? "? " : "");
printf("prechar : %c\n", escseq.pre);
printf("private : %c\n", escseq.priv ? '?' : ' ');
printf("narg : %d\n", escseq.narg);
if(escseq.narg) if(escseq.narg)
for(i = 0; i < escseq.narg; i++) for(i = 0; i < escseq.narg; i++)
printf("\targ %d = %d\n", i, escseq.arg[i]); printf("%d ", escseq.arg[i]);
printf("mode : %c\n", escseq.mode); if(escseq.mode)
putchar(escseq.mode);
putchar('\n');
} }
void void
escreset(void) { csireset(void) {
memset(&escseq, 0, sizeof(escseq)); memset(&escseq, 0, sizeof(escseq));
} }
@ -781,21 +743,41 @@ tputtab(void) {
void void
tputc(char c) { tputc(char c) {
static int inesc = 0;
#if 0 #if 0
dump(c); dump(c);
#endif #endif
/* start of escseq */ if(term.esc & ESCin) {
if(c == '\033') if(term.esc & ESCcsi) {
escreset(), inesc = 1; escseq.buf[escseq.len++] = c;
else if(inesc) { if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) {
inesc = escaddc(c); term.esc = 0;
} /* normal char */ csiparse(), csihandle();
else switch(c) { }
default: } else if (term.esc & ESCosc) {
tsetchar(c); if(c == ';') {
tcursor(CSright); term.titlelen = 0;
break; 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': case '\t':
tputtab(); tputtab();
break; break;
@ -811,6 +793,15 @@ tputc(char c) {
case '\a': case '\a':
xbell(); xbell();
break; break;
case '\033':
csireset();
term.esc = ESCin;
break;
default:
tsetchar(c);
tcursor(CSright);
break;
}
} }
} }