X-Git-Url: https://jasonwoof.com/gitweb/?p=st.git;a=blobdiff_plain;f=st.c;h=e19cefd949c60886de515b4fad18b09b2232fa52;hp=67b4942cdb42108922c3897ac5016669dfb29b4d;hb=ee3fbeb6c8c354cf4db226a5b1583c531ea37af4;hpb=0cc7ee5e737c9df5a41a4bca708e583117830085 diff --git a/st.c b/st.c index 67b4942..e19cefd 100644 --- a/st.c +++ b/st.c @@ -72,6 +72,8 @@ #define X2COL(x) (((x) - BORDER)/xw.cw) #define Y2ROW(y) (((y) - BORDER)/xw.ch) +#define VT102ID "\033[?6c" + enum glyph_attribute { ATTR_NULL = 0, ATTR_REVERSE = 1, @@ -121,6 +123,7 @@ enum escape_state { ESC_STR = 4, /* DSC, OSC, PM, APC */ ESC_ALTCHARSET = 8, ESC_STR_END = 16, /* a final string was encountered */ + ESC_TEST = 32, /* Enter in test mode */ }; enum window_state { @@ -287,7 +290,7 @@ static int tresize(int, int); static void tscrollup(int, int); static void tscrolldown(int, int); static void tsetattr(int*, int); -static void tsetchar(char*); +static void tsetchar(char *, Glyph *, int, int); static void tsetscroll(int, int); static void tswapscreen(void); static void tsetdirt(int, int); @@ -302,7 +305,6 @@ static void ttywrite(const char *, size_t); static void xdraws(char *, Glyph, int, int, int, int); static void xhints(void); static void xclear(int, int, int, int); -static void xclearborders(void); static void xdrawcursor(void); static void xinit(void); static void xloadcols(void); @@ -338,6 +340,7 @@ static int utf8encode(long *, char *); static int utf8size(char *); static int isfullutf8(char *, int); +static ssize_t xwrite(int, char *, size_t); static void *xmalloc(size_t); static void *xrealloc(void *, size_t); static void *xcalloc(size_t nmemb, size_t size); @@ -377,6 +380,21 @@ static char *opt_embed = NULL; static char *opt_class = NULL; static char *opt_font = NULL; + +ssize_t +xwrite(int fd, char *s, size_t len) { + size_t aux = len; + + while(len > 0) { + ssize_t r = write(fd, s, len); + if(r < 0) + return r; + len -= r; + s += r; + } + return aux; +} + void * xmalloc(size_t len) { void *p = malloc(len); @@ -876,7 +894,7 @@ execsh(void) { DEFAULT(envshell, SHELL); putenv("TERM="TNAME); - args = opt_cmd ? opt_cmd : (char*[]){envshell, "-i", NULL}; + args = opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL}; execvp(args[0], args); exit(EXIT_FAILURE); } @@ -924,13 +942,12 @@ ttynew(void) { cmdfd = m; signal(SIGCHLD, sigchld); if(opt_io) { - if(!strcmp(opt_io, "-")) { - iofd = STDOUT_FILENO; - } else { - if((iofd = open(opt_io, O_WRONLY | O_CREAT, 0666)) < 0) { - fprintf(stderr, "Error opening %s:%s\n", - opt_io, strerror(errno)); - } + iofd = (!strcmp(opt_io, "-")) ? + STDOUT_FILENO : + open(opt_io, O_WRONLY | O_CREAT, 0666); + if(iofd < 0) { + fprintf(stderr, "Error opening %s:%s\n", + opt_io, strerror(errno)); } } } @@ -1181,8 +1198,8 @@ tmoveto(int x, int y) { } void -tsetchar(char *c) { - char *vt100_0[62] = { /* 0x41 - 0x7e */ +tsetchar(char *c, Glyph *attr, int x, int y) { + static char *vt100_0[62] = { /* 0x41 - 0x7e */ "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ @@ -1196,17 +1213,17 @@ tsetchar(char *c) { /* * The table is proudly stolen from rxvt. */ - if(term.c.attr.mode & ATTR_GFX) { + if(attr->mode & ATTR_GFX) { if(c[0] >= 0x41 && c[0] <= 0x7e && vt100_0[c[0] - 0x41]) { c = vt100_0[c[0] - 0x41]; } } - term.dirty[term.c.y] = 1; - term.line[term.c.y][term.c.x] = term.c.attr; - memcpy(term.line[term.c.y][term.c.x].c, c, UTF_SIZ); - term.line[term.c.y][term.c.x].state |= GLYPH_SET; + term.dirty[y] = 1; + term.line[y][x] = *attr; + memcpy(term.line[y][x].c, c, UTF_SIZ); + term.line[y][x].state |= GLYPH_SET; } void @@ -1511,6 +1528,10 @@ csihandle(void) { DEFAULT(csiescseq.arg[0], 1); tmoveto(term.c.x, term.c.y+csiescseq.arg[0]); break; + case 'c': /* DA -- Device Attributes */ + if(csiescseq.arg[0] == 0) + ttywrite(VT102ID, sizeof(VT102ID) - 1); + break; case 'C': /* CUF -- Cursor Forward */ case 'a': DEFAULT(csiescseq.arg[0], 1); @@ -1785,40 +1806,86 @@ tputtab(bool forward) { void tputc(char *c, int len) { uchar ascii = *c; - - if(iofd != -1) - write(iofd, c, len); - - switch(ascii) { - case '\t': - tputtab(1); - return; - case '\b': - tmoveto(term.c.x-1, term.c.y); - return; - case '\r': - tmoveto(0, term.c.y); - return; - case '\f': - case '\v': - case '\n': - /* go to first col if the mode is set */ - tnewline(IS_SET(MODE_CRLF)); - return; - case '\a': - if(term.esc & ESC_STR) + bool control = ascii < '\x20' || ascii == 0177; + + if(iofd != -1) { + if (xwrite(iofd, c, len) < 0) { + fprintf(stderr, "Error writting in %s:%s\n", + opt_io, strerror(errno)); + close(iofd); + iofd = -1; + } + } + /* + * STR sequences must be checked before of anything + * because it can use some control codes as part of the sequence + */ + if(term.esc & ESC_STR) { + switch(ascii) { + case '\033': + term.esc = ESC_START | ESC_STR_END; break; - - if(!(xw.state & WIN_FOCUSED)) - xseturgency(1); - return; - case '\033': - csireset(); - term.esc = ESC_START; + case '\a': /* backwards compatibility to xterm */ + term.esc = 0; + strhandle(); + break; + default: + strescseq.buf[strescseq.len++] = ascii; + if(strescseq.len+1 >= STR_BUF_SIZ) { + term.esc = 0; + strhandle(); + } + } return; } - - if(term.esc & ESC_START) { + /* + * Actions of control codes must be performed as soon they arrive + * because they can be embedded inside a control sequence, and + * they must not cause conflicts with sequences. + */ + if(control) { + switch(ascii) { + case '\t': /* HT */ + tputtab(1); + return; + case '\b': /* BS */ + tmoveto(term.c.x-1, term.c.y); + return; + case '\r': /* CR */ + tmoveto(0, term.c.y); + return; + case '\f': /* LF */ + case '\v': /* VT */ + case '\n': /* LF */ + /* go to first col if the mode is set */ + tnewline(IS_SET(MODE_CRLF)); + return; + case '\a': /* BEL */ + if(!(xw.state & WIN_FOCUSED)) + xseturgency(1); + return; + case '\033': /* ESC */ + csireset(); + term.esc = ESC_START; + return; + case '\016': /* SO */ + term.c.attr.mode |= ATTR_GFX; + return; + case '\017': /* SI */ + term.c.attr.mode &= ~ATTR_GFX; + return; + case '\032': /* SUB */ + case '\030': /* CAN */ + csireset(); + return; + case '\005': /* ENQ (IGNORED) */ + case '\000': /* NUL (IGNORED) */ + case '\021': /* XON (IGNORED) */ + case '\023': /* XOFF (IGNORED) */ + case 0177: /* DEL (IGNORED) */ + return; + } + } else if(term.esc & ESC_START) { if(term.esc & ESC_CSI) { csiescseq.buf[csiescseq.len++] = ascii; if(BETWEEN(ascii, 0x40, 0x7E) @@ -1826,22 +1893,6 @@ tputc(char *c, int len) { term.esc = 0; csiparse(), csihandle(); } - } 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; - 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 == '\\') @@ -1864,11 +1915,25 @@ tputc(char *c, int len) { fprintf(stderr, "esc unhandled charset: ESC ( %c\n", ascii); } term.esc = 0; + } else if(term.esc & ESC_TEST) { + if(ascii == '8') { /* DEC screen alignment test. */ + char E[UTF_SIZ] = "E"; + int x, y; + + for(x = 0; x < term.col; ++x) { + for(y = 0; y < term.row; ++y) + tsetchar(E, &term.c.attr, x, y); + } + } + term.esc = 0; } else { switch(ascii) { case '[': term.esc |= ESC_CSI; break; + case '#': + term.esc |= ESC_TEST; + break; case 'P': /* DCS -- Device Control String */ case '_': /* APC -- Application Program Command */ case '^': /* PM -- Privacy Message */ @@ -1910,6 +1975,10 @@ tputc(char *c, int len) { } term.esc = 0; break; + case 'Z': /* DECID -- Identify Terminal */ + ttywrite(VT102ID, sizeof(VT102ID) - 1); + term.esc = 0; + break; case 'c': /* RIS -- Reset to inital state */ treset(); term.esc = 0; @@ -1940,20 +2009,26 @@ tputc(char *c, int len) { term.esc = 0; } } - } else { - if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey)) - sel.bx = -1; - if(ascii >= '\020' || term.c.attr.mode & ATTR_GFX) { - if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT) - tnewline(1); /* always go to first col */ - tsetchar(c); - if(term.c.x+1 < term.col) { - tmoveto(term.c.x+1, term.c.y); - } else { - term.c.state |= CURSOR_WRAPNEXT; - } - } + /* + * All characters which forms part of a sequence are not + * printed + */ + return; } + /* + * Display control codes only if we are in graphic mode + */ + if(control && !(term.c.attr.mode & ATTR_GFX)) + return; + if(sel.bx != -1 && BETWEEN(term.c.y, sel.by, sel.ey)) + sel.bx = -1; + if(IS_SET(MODE_WRAP) && term.c.state & CURSOR_WRAPNEXT) + tnewline(1); /* always go to first col */ + tsetchar(c, &term.c.attr, term.c.x, term.c.y); + if(term.c.x+1 < term.col) + tmoveto(term.c.x+1, term.c.y); + else + term.c.state |= CURSOR_WRAPNEXT; } int @@ -2281,7 +2356,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { * Those ranges will not be brightened: * 8 - 15 – bright system colors * 196 - 231 – highest 256 color cube - * 252 - 255 – brightest colors in grescale + * 252 - 255 – brightest colors in greyscale */ font = &dc.bfont; } @@ -2326,7 +2401,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { } if(x + charlen >= term.col-1) { xclear(winx + width, (y == 0)? 0 : winy, xw.w, - winy + xw.ch + (y == term.row-1)? xw.h : 0); + (y == term.row-1)? xw.h : (winy + xw.ch)); } if(y == 0) xclear(winx, 0, winx + width, BORDER);