diff --git a/st.c b/st.c index 17a0709..a84f0e0 100644 --- a/st.c +++ b/st.c @@ -20,11 +20,12 @@ #include #include -#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
 [[ []  [;]] ] */
+/* CSI Escape sequence structs */
+/* ESC '[' [[ []  [;]] ] */
 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  blank char */
-			DEFAULT(escseq.arg[0], 1);
-			tinsertblank(escseq.arg[0]);
-			break;
-		case 'A': /* Cursor  Up */
-		case 'e':
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x, term.c.y-escseq.arg[0]);
-			break;
-		case 'B': /* Cursor  Down */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x, term.c.y+escseq.arg[0]);
-			break;
-		case 'C': /* Cursor  Forward */
-		case 'a':
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x+escseq.arg[0], term.c.y);
-			break;
-		case 'D': /* Cursor  Backward */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(term.c.x-escseq.arg[0], term.c.y);
-			break;
-		case 'E': /* Cursor  Down and first col */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(0, term.c.y+escseq.arg[0]);
-			break;
-		case 'F': /* Cursor  Up and first col */
-			DEFAULT(escseq.arg[0], 1);
-			tmoveto(0, term.c.y-escseq.arg[0]);
-			break;
-		case 'G': /* Move to  */
-		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  blank char */
+		DEFAULT(escseq.arg[0], 1);
+		tinsertblank(escseq.arg[0]);
+		break;
+	case 'A': /* Cursor  Up */
+	case 'e':
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x, term.c.y-escseq.arg[0]);
+		break;
+	case 'B': /* Cursor  Down */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x, term.c.y+escseq.arg[0]);
+		break;
+	case 'C': /* Cursor  Forward */
+	case 'a':
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x+escseq.arg[0], term.c.y);
+		break;
+	case 'D': /* Cursor  Backward */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(term.c.x-escseq.arg[0], term.c.y);
+		break;
+	case 'E': /* Cursor  Down and first col */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(0, term.c.y+escseq.arg[0]);
+		break;
+	case 'F': /* Cursor  Up and first col */
+		DEFAULT(escseq.arg[0], 1);
+		tmoveto(0, term.c.y-escseq.arg[0]);
+		break;
+	case 'G': /* Move to  */
+	case '`':
+		DEFAULT(escseq.arg[0], 1);
+     	tmoveto(escseq.arg[0]-1, term.c.y);
+		break;
+	case 'H': /* Move to   */
+	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   */
-		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  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  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  lines */
-			DEFAULT(escseq.arg[0], 1);
-			tdeleteline(escseq.arg[0]);
-			break;
-		case 'P': /* Delete  char */
-			DEFAULT(escseq.arg[0], 1);
-			tdeletechar(escseq.arg[0]);
-			break;
-		case 'd': /* Move to  */
+		break;
+	case 'M': /* Delete  lines */
+		DEFAULT(escseq.arg[0], 1);
+		tdeleteline(escseq.arg[0]);
+		break;
+	case 'X':
+	case 'P': /* Delete  char */
+		DEFAULT(escseq.arg[0], 1);
+		tdeletechar(escseq.arg[0]);
+		break;
+	case 'd': /* Move to  */
+		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;
+		}
 	}
 }