aboutsummaryrefslogtreecommitdiff
path: root/st.c
diff options
context:
space:
mode:
Diffstat (limited to 'st.c')
-rw-r--r--st.c389
1 files changed, 190 insertions, 199 deletions
diff --git a/st.c b/st.c
index 17a0709..a84f0e0 100644
--- a/st.c
+++ b/st.c
@@ -20,11 +20,12 @@
20#include <X11/keysym.h> 20#include <X11/keysym.h>
21#include <X11/Xutil.h> 21#include <X11/Xutil.h>
22 22
23#define TNAME "st" 23#define TNAME "xterm"
24 24
25/* Arbitrary sizes */ 25/* Arbitrary sizes */
26#define TITLESIZ 256
26#define ESCSIZ 256 27#define ESCSIZ 256
27#define ESCARG 16 28#define ESCARGSIZ 16
28#define MAXDRAWBUF 1024 29#define MAXDRAWBUF 1024
29 30
30#define SERRNO strerror(errno) 31#define SERRNO strerror(errno)
@@ -40,7 +41,8 @@
40enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 }; 41enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4 };
41enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload }; 42enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSwrap, CSsave, CSload };
42enum { CRset=1, CRupdate=2 }; 43enum { CRset=1, CRupdate=2 };
43enum { TMwrap=1, TMinsert=2 }; 44enum { TMwrap=1, TMinsert=2, TMtitle=4 };
45enum { ESCin = 1, ESCcsi = 2, ESCosc = 4, ESCtitle = 8 };
44enum { SCupdate, SCredraw }; 46enum { SCupdate, SCredraw };
45 47
46typedef int Color; 48typedef int Color;
@@ -62,17 +64,16 @@ typedef struct {
62 int y; 64 int y;
63} TCursor; 65} TCursor;
64 66
65/* Escape sequence structs */ 67/* CSI Escape sequence structs */
66/* ESC <pre> [[ [<priv>] <arg> [;]] <mode>] */ 68/* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */
67typedef struct { 69typedef struct {
68 char buf[ESCSIZ+1]; /* raw string */ 70 char buf[ESCSIZ]; /* raw string */
69 int len; /* raw string length */ 71 int len; /* raw string length */
70 char pre;
71 char priv; 72 char priv;
72 int arg[ESCARG+1]; 73 int arg[ESCARGSIZ];
73 int narg; /* nb of args */ 74 int narg; /* nb of args */
74 char mode; 75 char mode;
75} Escseq; 76} CSIEscape;
76 77
77/* Internal representation of the screen */ 78/* Internal representation of the screen */
78typedef struct { 79typedef struct {
@@ -83,6 +84,9 @@ typedef struct {
83 int top; /* top scroll limit */ 84 int top; /* top scroll limit */
84 int bot; /* bottom scroll limit */ 85 int bot; /* bottom scroll limit */
85 int mode; /* terminal mode */ 86 int mode; /* terminal mode */
87 int esc;
88 char title[TITLESIZ];
89 int titlelen;
86} Term; 90} Term;
87 91
88/* Purely graphic info */ 92/* Purely graphic info */
@@ -116,12 +120,10 @@ static void execsh(void);
116static void sigchld(int); 120static void sigchld(int);
117static void run(void); 121static void run(void);
118 122
119static int escaddc(char); 123static void csidump(void);
120static int escfinal(char); 124static void csihandle(void);
121static void escdump(void); 125static void csiparse(void);
122static void eschandle(void); 126static void csireset(void);
123static void escparse(void);
124static void escreset(void);
125 127
126static void tclearregion(int, int, int, int); 128static void tclearregion(int, int, int, int);
127static void tcpos(int); 129static void tcpos(int);
@@ -168,7 +170,7 @@ static void (*handler[LASTEvent])(XEvent *) = {
168static DC dc; 170static DC dc;
169static XWindow xw; 171static XWindow xw;
170static Term term; 172static Term term;
171static Escseq escseq; 173static CSIEscape escseq;
172static int cmdfd; 174static int cmdfd;
173static pid_t pid; 175static pid_t pid;
174static int running; 176static int running;
@@ -269,7 +271,7 @@ ttynew(void) {
269void 271void
270dump(char c) { 272dump(char c) {
271 static int col; 273 static int col;
272 fprintf(stderr, " %02x %c ", c, isprint(c)?c:'.'); 274 fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
273 if(++col % 10 == 0) 275 if(++col % 10 == 0)
274 fprintf(stderr, "\n"); 276 fprintf(stderr, "\n");
275} 277}
@@ -305,24 +307,6 @@ ttyresize(int x, int y) {
305 fprintf(stderr, "Couldn't set window size: %s\n", SERRNO); 307 fprintf(stderr, "Couldn't set window size: %s\n", SERRNO);
306} 308}
307 309
308int
309escfinal(char c) {
310 if(escseq.len == 1)
311 switch(c) {
312 case '[':
313 case ']':
314 case '(':
315 return 0;
316 case '=':
317 case '>':
318 default:
319 return 1;
320 }
321 else if(BETWEEN(c, 0x40, 0x7E))
322 return 1;
323 return 0;
324}
325
326void 310void
327tcpos(int mode) { 311tcpos(int mode) {
328 static int x = 0; 312 static int x = 0;
@@ -372,44 +356,27 @@ tnewline(void) {
372 tmoveto(0, y); 356 tmoveto(0, y);
373} 357}
374 358
375int
376escaddc(char c) {
377 escseq.buf[escseq.len++] = c;
378 if(escfinal(c) || escseq.len >= ESCSIZ) {
379 escparse(), eschandle();
380 return 0;
381 }
382 return 1;
383}
384
385void 359void
386escparse(void) { 360csiparse(void) {
387 /* int noarg = 1; */ 361 /* int noarg = 1; */
388 char *p = escseq.buf; 362 char *p = escseq.buf;
389 363
390 escseq.narg = 0; 364 escseq.narg = 0;
391 switch(escseq.pre = *p++) { 365 if(*p == '?')
392 case '[': /* CSI */ 366 escseq.priv = 1, p++;
393 if(*p == '?') 367
394 escseq.priv = 1, p++; 368 while(p < escseq.buf+escseq.len) {
395 369 while(isdigit(*p)) {
396 while(p < escseq.buf+escseq.len) { 370 escseq.arg[escseq.narg] *= 10;
397 while(isdigit(*p)) { 371 escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */;
398 escseq.arg[escseq.narg] *= 10; 372 }
399 escseq.arg[escseq.narg] += *(p++) - '0'/*, noarg = 0 */; 373 if(*p == ';' && escseq.narg+1 < ESCARGSIZ)
400 } 374 escseq.narg++, p++;
401 if(*p == ';') 375 else {
402 escseq.narg++, p++; 376 escseq.mode = *p;
403 else { 377 escseq.narg++;
404 escseq.mode = *p; 378 return;
405 escseq.narg++;
406 return;
407 }
408 } 379 }
409 break;
410 case '(':
411 /* XXX: graphic character set */
412 break;
413 } 380 }
414} 381}
415 382
@@ -625,146 +592,141 @@ tsetscroll(int t, int b) {
625} 592}
626 593
627void 594void
628eschandle(void) { 595csihandle(void) {
629 switch(escseq.pre) { 596 switch(escseq.mode) {
630 default: 597 default:
631 goto unknown_seq; 598 fprintf(stderr, "erresc: unknown sequence\n");
632 case '[': 599 csidump();
633 switch(escseq.mode) { 600 /* die(""); */
634 default: 601 break;
635 unknown_seq: 602 case '@': /* Insert <n> blank char */
636 fprintf(stderr, "erresc: unknown sequence\n"); 603 DEFAULT(escseq.arg[0], 1);
637 escdump(); 604 tinsertblank(escseq.arg[0]);
638 break; 605 break;
639 case '@': /* Insert <n> blank char */ 606 case 'A': /* Cursor <n> Up */
640 DEFAULT(escseq.arg[0], 1); 607 case 'e':
641 tinsertblank(escseq.arg[0]); 608 DEFAULT(escseq.arg[0], 1);
642 break; 609 tmoveto(term.c.x, term.c.y-escseq.arg[0]);
643 case 'A': /* Cursor <n> Up */ 610 break;
644 case 'e': 611 case 'B': /* Cursor <n> Down */
645 DEFAULT(escseq.arg[0], 1); 612 DEFAULT(escseq.arg[0], 1);
646 tmoveto(term.c.x, term.c.y-escseq.arg[0]); 613 tmoveto(term.c.x, term.c.y+escseq.arg[0]);
647 break; 614 break;
648 case 'B': /* Cursor <n> Down */ 615 case 'C': /* Cursor <n> Forward */
649 DEFAULT(escseq.arg[0], 1); 616 case 'a':
650 tmoveto(term.c.x, term.c.y+escseq.arg[0]); 617 DEFAULT(escseq.arg[0], 1);
651 break; 618 tmoveto(term.c.x+escseq.arg[0], term.c.y);
652 case 'C': /* Cursor <n> Forward */ 619 break;
653 case 'a': 620 case 'D': /* Cursor <n> Backward */
654 DEFAULT(escseq.arg[0], 1); 621 DEFAULT(escseq.arg[0], 1);
655 tmoveto(term.c.x+escseq.arg[0], term.c.y); 622 tmoveto(term.c.x-escseq.arg[0], term.c.y);
656 break; 623 break;
657 case 'D': /* Cursor <n> Backward */ 624 case 'E': /* Cursor <n> Down and first col */
658 DEFAULT(escseq.arg[0], 1); 625 DEFAULT(escseq.arg[0], 1);
659 tmoveto(term.c.x-escseq.arg[0], term.c.y); 626 tmoveto(0, term.c.y+escseq.arg[0]);
660 break; 627 break;
661 case 'E': /* Cursor <n> Down and first col */ 628 case 'F': /* Cursor <n> Up and first col */
662 DEFAULT(escseq.arg[0], 1); 629 DEFAULT(escseq.arg[0], 1);
663 tmoveto(0, term.c.y+escseq.arg[0]); 630 tmoveto(0, term.c.y-escseq.arg[0]);
664 break; 631 break;
665 case 'F': /* Cursor <n> Up and first col */ 632 case 'G': /* Move to <col> */
666 DEFAULT(escseq.arg[0], 1); 633 case '`':
667 tmoveto(0, term.c.y-escseq.arg[0]); 634 DEFAULT(escseq.arg[0], 1);
668 break; 635 tmoveto(escseq.arg[0]-1, term.c.y);
669 case 'G': /* Move to <col> */ 636 break;
670 case '`': 637 case 'H': /* Move to <row> <col> */
671 DEFAULT(escseq.arg[0], 1); 638 case 'f':
672 tmoveto(escseq.arg[0]-1, term.c.y); 639 DEFAULT(escseq.arg[0], 1);
640 DEFAULT(escseq.arg[1], 1);
641 tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
642 break;
643 case 'J': /* Clear screen */
644 switch(escseq.arg[0]) {
645 case 0: /* below */
646 tclearregion(term.c.x, term.c.y, term.col-1, term.row-1);
673 break; 647 break;
674 case 'H': /* Move to <row> <col> */ 648 case 1: /* above */
675 case 'f': 649 tclearregion(0, 0, term.c.x, term.c.y);
676 DEFAULT(escseq.arg[0], 1);
677 DEFAULT(escseq.arg[1], 1);
678 tmoveto(escseq.arg[1]-1, escseq.arg[0]-1);
679 break; 650 break;
680 case 'J': /* Clear screen */ 651 case 2: /* all */
681 switch(escseq.arg[0]) { 652 tclearregion(0, 0, term.col-1, term.row-1);
682 case 0: /* below */ 653 break;
683 tclearregion(term.c.x, term.c.y, term.col-1, term.row-1); 654 }
684 break; 655 break;
685 case 1: /* above */ 656 case 'K': /* Clear line */
686 tclearregion(0, 0, term.c.x, term.c.y); 657 switch(escseq.arg[0]) {
687 break; 658 case 0: /* right */
688 case 2: /* all */ 659 tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
689 tclearregion(0, 0, term.col-1, term.row-1);
690 break;
691 }
692 break; 660 break;
693 case 'K': /* Clear line */ 661 case 1: /* left */
694 switch(escseq.arg[0]) { 662 tclearregion(0, term.c.y, term.c.x, term.c.y);
695 case 0: /* right */
696 tclearregion(term.c.x, term.c.y, term.col-1, term.c.y);
697 break;
698 case 1: /* left */
699 tclearregion(0, term.c.y, term.c.x, term.c.y);
700 break;
701 case 2: /* all */
702 tclearregion(0, term.c.y, term.col-1, term.c.y);
703 break;
704 }
705 break; 663 break;
706 case 'L': /* Insert <n> blank lines */ 664 case 2: /* all */
707 DEFAULT(escseq.arg[0], 1); 665 tclearregion(0, term.c.y, term.col-1, term.c.y);
708 tinsertblankline(escseq.arg[0]);
709 break; 666 break;
710 case 'l': 667 }
711 if(escseq.priv && escseq.arg[0] == 25) 668 break;
669 case 'S':
670 case 'L': /* Insert <n> blank lines */
671 DEFAULT(escseq.arg[0], 1);
672 tinsertblankline(escseq.arg[0]);
673 break;
674 case 'l':
675 if(escseq.priv && escseq.arg[0] == 25)
712 term.c.hidden = 1; 676 term.c.hidden = 1;
713 break; 677 break;
714 case 'M': /* Delete <n> lines */ 678 case 'M': /* Delete <n> lines */
715 DEFAULT(escseq.arg[0], 1); 679 DEFAULT(escseq.arg[0], 1);
716 tdeleteline(escseq.arg[0]); 680 tdeleteline(escseq.arg[0]);
717 break; 681 break;
718 case 'P': /* Delete <n> char */ 682 case 'X':
719 DEFAULT(escseq.arg[0], 1); 683 case 'P': /* Delete <n> char */
720 tdeletechar(escseq.arg[0]); 684 DEFAULT(escseq.arg[0], 1);
721 break; 685 tdeletechar(escseq.arg[0]);
722 case 'd': /* Move to <row> */ 686 break;
687 case 'd': /* Move to <row> */
688 DEFAULT(escseq.arg[0], 1);
689 tmoveto(term.c.x, escseq.arg[0]-1);
690 break;
691 case 'h': /* Set terminal mode */
692 if(escseq.priv && escseq.arg[0] == 25)
693 term.c.hidden = 0;
694 break;
695 case 'm': /* Terminal attribute (color) */
696 tsetattr(escseq.arg, escseq.narg);
697 break;
698 case 'r':
699 if(escseq.priv)
700 ;
701 else {
723 DEFAULT(escseq.arg[0], 1); 702 DEFAULT(escseq.arg[0], 1);
724 tmoveto(term.c.x, escseq.arg[0]-1); 703 DEFAULT(escseq.arg[1], term.row);
725 break; 704 tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
726 case 'h': /* Set terminal mode */
727 if(escseq.priv && escseq.arg[0] == 25)
728 term.c.hidden = 0;
729 break;
730 case 'm': /* Terminal attribute (color) */
731 tsetattr(escseq.arg, escseq.narg);
732 break;
733 case 'r':
734 if(escseq.priv)
735 ;
736 else {
737 DEFAULT(escseq.arg[0], 1);
738 DEFAULT(escseq.arg[1], term.row);
739 tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1);
740 }
741 break;
742 case 's': /* Save cursor position */
743 tcpos(CSsave);
744 break;
745 case 'u': /* Load cursor position */
746 tcpos(CSload);
747 break;
748 } 705 }
749 break; 706 break;
707 case 's': /* Save cursor position */
708 tcpos(CSsave);
709 break;
710 case 'u': /* Load cursor position */
711 tcpos(CSload);
712 break;
750 } 713 }
751} 714}
752 715
753void 716void
754escdump(void) { 717csidump(void) {
755 int i; 718 int i;
756 printf("rawbuf : %s\n", escseq.buf); 719 printf("ESC [ %s", escseq.priv ? "? " : "");
757 printf("prechar : %c\n", escseq.pre);
758 printf("private : %c\n", escseq.priv ? '?' : ' ');
759 printf("narg : %d\n", escseq.narg);
760 if(escseq.narg) 720 if(escseq.narg)
761 for(i = 0; i < escseq.narg; i++) 721 for(i = 0; i < escseq.narg; i++)
762 printf("\targ %d = %d\n", i, escseq.arg[i]); 722 printf("%d ", escseq.arg[i]);
763 printf("mode : %c\n", escseq.mode); 723 if(escseq.mode)
724 putchar(escseq.mode);
725 putchar('\n');
764} 726}
765 727
766void 728void
767escreset(void) { 729csireset(void) {
768 memset(&escseq, 0, sizeof(escseq)); 730 memset(&escseq, 0, sizeof(escseq));
769} 731}
770 732
@@ -781,21 +743,41 @@ tputtab(void) {
781 743
782void 744void
783tputc(char c) { 745tputc(char c) {
784 static int inesc = 0;
785#if 0 746#if 0
786 dump(c); 747 dump(c);
787#endif 748#endif
788 /* start of escseq */ 749 if(term.esc & ESCin) {
789 if(c == '\033') 750 if(term.esc & ESCcsi) {
790 escreset(), inesc = 1; 751 escseq.buf[escseq.len++] = c;
791 else if(inesc) { 752 if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) {
792 inesc = escaddc(c); 753 term.esc = 0;
793 } /* normal char */ 754 csiparse(), csihandle();
794 else switch(c) { 755 }
795 default: 756 } else if (term.esc & ESCosc) {
796 tsetchar(c); 757 if(c == ';') {
797 tcursor(CSright); 758 term.titlelen = 0;
798 break; 759 term.esc = ESCin | ESCtitle;
760 }
761 } else if(term.esc & ESCtitle) {
762 if(c == '\a' || term.titlelen+1 >= TITLESIZ) {
763 term.esc = 0;
764 term.title[term.titlelen] = '\0';
765 XStoreName(xw.dis, xw.win, term.title);
766 } else {
767 term.title[term.titlelen++] = c;
768 }
769 } else {
770 switch(c) {
771 case '[':
772 term.esc |= ESCcsi;
773 break;
774 case ']':
775 term.esc |= ESCosc;
776 break;
777 }
778 }
779 } else {
780 switch(c) {
799 case '\t': 781 case '\t':
800 tputtab(); 782 tputtab();
801 break; 783 break;
@@ -811,6 +793,15 @@ tputc(char c) {
811 case '\a': 793 case '\a':
812 xbell(); 794 xbell();
813 break; 795 break;
796 case '\033':
797 csireset();
798 term.esc = ESCin;
799 break;
800 default:
801 tsetchar(c);
802 tcursor(CSright);
803 break;
804 }
814 } 805 }
815} 806}
816 807