X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=st.c;h=d954288508f8432fae0efd78749e467931973bea;hb=190b94c7a2a7bb2f5d55cbb6eb1779fd042c6467;hp=f9aba901b62726086eef095721bd2db6104aac6b;hpb=0d7448dabc981716d277a5afac22fabc127bacca;p=st.git diff --git a/st.c b/st.c index f9aba90..d954288 100644 --- a/st.c +++ b/st.c @@ -72,6 +72,7 @@ char *argv0; #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) +#define ISDELIM(u) (BETWEEN(u, 0, 127) && strchr(worddelimiters, u) != NULL) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) #define IS_SET(flag) ((term.mode & (flag)) != 0) @@ -180,10 +181,10 @@ typedef XftDraw *Draw; typedef XftColor Color; typedef struct { - char c[UTF_SIZ]; /* character code */ + long u; /* character code */ ushort mode; /* attribute flags */ - uint32_t fg; /* foreground */ - uint32_t bg; /* background */ + ushort fg; /* foreground */ + ushort bg; /* background */ } Glyph; typedef Glyph *Line; @@ -382,20 +383,20 @@ static void tmoveato(int, int); static void tnew(int, int); static void tnewline(int); static void tputtab(int); -static void tputc(char *, int); +static void tputc(long); static void treset(void); static void tresize(int, int); static void tscrollup(int, int); static void tscrolldown(int, int); static void tsetattr(int *, int); -static void tsetchar(char *, Glyph *, int, int); +static void tsetchar(long, Glyph *, int, int); static void tsetscroll(int, int); static void tswapscreen(void); static void tsetdirt(int, int); static void tsetdirtattr(int); static void tsetmode(bool, bool, int *, int); static void tfulldirt(void); -static void techo(char *, int); +static void techo(long); static void tcontrolcode(uchar ); static void tdectest(char ); static int32_t tdefcolor(int *, int *, int); @@ -410,6 +411,7 @@ static void tstrsequence(uchar); static inline ushort sixd_to_16bit(int); static void xdraws(char *, Glyph, int, int, int, int); +static void xdrawglyph(Glyph, int, int); static void xhints(void); static void xclear(int, int, int, int); static void xdrawcursor(void); @@ -459,9 +461,8 @@ static void mousereport(XEvent *); static size_t utf8decode(char *, long *, size_t); static long utf8decodebyte(char, size_t *); -static size_t utf8encode(long, char *, size_t); +static size_t utf8encode(long, char *); static char utf8encodebyte(long, size_t); -static size_t utf8len(char *); static size_t utf8validate(long *, size_t); static ssize_t xwrite(int, const char *, size_t); @@ -610,11 +611,11 @@ utf8decodebyte(char c, size_t *i) { } size_t -utf8encode(long u, char *c, size_t clen) { +utf8encode(long u, char *c) { size_t len, i; len = utf8validate(&u, 0); - if(clen < len) + if(len > UTF_SIZ) return 0; for(i = len - 1; i != 0; --i) { c[i] = utf8encodebyte(u, 0); @@ -629,11 +630,6 @@ utf8encodebyte(long u, size_t i) { return utfbyte[i] | (u & ~utfmask[i]); } -size_t -utf8len(char *c) { - return utf8decode(c, &(long){0}, UTF_SIZ); -} - size_t utf8validate(long *u, size_t i) { if(!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF)) @@ -679,7 +675,7 @@ tlinelen(int y) { if(term.line[y][i - 1].mode & ATTR_WRAP) return i; - while(i > 0 && term.line[y][i - 1].c[0] == ' ') + while(i > 0 && term.line[y][i - 1].u == ' ') --i; return i; @@ -736,7 +732,7 @@ selsnap(int mode, int *x, int *y, int direction) { * beginning of a line. */ prevgp = &term.line[*y][*x]; - prevdelim = strchr(worddelimiters, prevgp->c[0]) != NULL; + prevdelim = ISDELIM(prevgp->u); for(;;) { newx = *x + direction; newy = *y; @@ -758,9 +754,9 @@ selsnap(int mode, int *x, int *y, int direction) { break; gp = &term.line[newy][newx]; - delim = strchr(worddelimiters, gp->c[0]) != NULL; + delim = ISDELIM(gp->u); if(!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim - || (delim && gp->c[0] != prevgp->c[0]))) + || (delim && gp->u != prevgp->u))) break; *x = newx; @@ -859,12 +855,11 @@ mousereport(XEvent *e) { } if(!IS_SET(MODE_MOUSEX10)) { - button += (state & ShiftMask ? 4 : 0) - + (state & Mod4Mask ? 8 : 0) - + (state & ControlMask ? 16 : 0); + button += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod4Mask ) ? 8 : 0) + + ((state & ControlMask) ? 16 : 0); } - len = 0; if(IS_SET(MODE_MOUSESGR)) { len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", button, x+1, y+1, @@ -936,7 +931,7 @@ bpress(XEvent *e) { char * getsel(void) { char *str, *ptr; - int y, bufsize, size, lastx, linelen; + int y, bufsize, lastx, linelen; Glyph *gp, *last; if(sel.ob.x == -1) @@ -957,16 +952,14 @@ getsel(void) { lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1; } last = &term.line[y][MIN(lastx, linelen-1)]; - while(last >= gp && last->c[0] == ' ') + while(last >= gp && last->u == ' ') --last; for( ; gp <= last; ++gp) { if(gp->mode & ATTR_WDUMMY) continue; - size = utf8len(gp->c); - memcpy(ptr, gp->c, size); - ptr += size; + ptr += utf8encode(gp->u, ptr); } /* @@ -1276,7 +1269,8 @@ stty(void) siz-= n + 1; } *q = '\0'; - system(cmd); + if (system(cmd) != 0) + perror("Couldn't call stty"); } void @@ -1337,7 +1331,6 @@ ttyread(void) { static char buf[BUFSIZ]; static int buflen = 0; char *ptr; - char s[UTF_SIZ]; int charsize; /* size of utf8 char in bytes */ long unicodep; int ret; @@ -1350,8 +1343,7 @@ ttyread(void) { buflen += ret; ptr = buf; while((charsize = utf8decode(ptr, &unicodep, buflen))) { - utf8encode(unicodep, s, UTF_SIZ); - tputc(s, charsize); + tputc(unicodep); ptr += charsize; buflen -= charsize; } @@ -1368,9 +1360,16 @@ ttywrite(const char *s, size_t n) { void ttysend(char *s, size_t n) { + int len; + long u; + ttywrite(s, n); if(IS_SET(MODE_ECHO)) - techo(s, n); + while((len = utf8decode(s, &u, n)) > 0) { + techo(u); + n -= len; + s += len; + } } void @@ -1619,7 +1618,7 @@ tmoveto(int x, int y) { } void -tsetchar(char *c, Glyph *attr, int x, int y) { +tsetchar(long u, 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 */ @@ -1634,25 +1633,23 @@ tsetchar(char *c, Glyph *attr, int x, int y) { /* * The table is proudly stolen from rxvt. */ - if(term.trantbl[term.charset] == CS_GRAPHIC0) { - if(BETWEEN(c[0], 0x41, 0x7e) && vt100_0[c[0] - 0x41]) { - c = vt100_0[c[0] - 0x41]; - } - } + if(term.trantbl[term.charset] == CS_GRAPHIC0 && + BETWEEN(u, 0x41, 0x7e) && vt100_0[u - 0x41]) + utf8decode(vt100_0[u - 0x41], &u, UTF_SIZ); if(term.line[y][x].mode & ATTR_WIDE) { if(x+1 < term.col) { - term.line[y][x+1].c[0] = ' '; + term.line[y][x+1].u = ' '; term.line[y][x+1].mode &= ~ATTR_WDUMMY; } } else if(term.line[y][x].mode & ATTR_WDUMMY) { - term.line[y][x-1].c[0] = ' '; + term.line[y][x-1].u = ' '; term.line[y][x-1].mode &= ~ATTR_WIDE; } term.dirty[y] = 1; term.line[y][x] = *attr; - memcpy(term.line[y][x].c, c, UTF_SIZ); + term.line[y][x].u = u; } void @@ -1679,7 +1676,7 @@ tclearregion(int x1, int y1, int x2, int y2) { gp->fg = term.c.attr.fg; gp->bg = term.c.attr.bg; gp->mode = 0; - memcpy(gp->c, " ", 2); + gp->u = ' '; } } } @@ -1746,7 +1743,7 @@ tdefcolor(int *attr, int *npar, int l) { b = attr[*npar + 4]; *npar += 4; if(!BETWEEN(r, 0, 255) || !BETWEEN(g, 0, 255) || !BETWEEN(b, 0, 255)) - fprintf(stderr, "erresc: bad rgb color (%d,%d,%d)\n", + fprintf(stderr, "erresc: bad rgb color (%u,%u,%u)\n", r, g, b); else idx = TRUECOLOR(r, g, b); @@ -2399,13 +2396,14 @@ tdumpsel(void) { void tdumpline(int n) { + char buf[UTF_SIZ]; Glyph *bp, *end; bp = &term.line[n][0]; end = &bp[MIN(tlinelen(n), term.col) - 1]; - if(bp != end || bp->c[0] != ' ') { + if(bp != end || bp->u != ' ') { for( ;bp <= end; ++bp) - tprinter(bp->c, utf8len(bp->c)); + tprinter(buf, utf8encode(bp->u, buf)); } tprinter("\n", 1); } @@ -2435,26 +2433,18 @@ tputtab(int n) { } void -techo(char *buf, int len) { - for(; len > 0; buf++, len--) { - char c = *buf; - - if(ISCONTROL((uchar) c)) { /* control code */ - if(c & 0x80) { - c &= 0x7f; - tputc("^", 1); - tputc("[", 1); - } else if(c != '\n' && c != '\r' && c != '\t') { - c ^= 0x40; - tputc("^", 1); - } - tputc(&c, 1); - } else { - break; +techo(long u) { + if(ISCONTROL(u)) { /* control code */ + if(u & 0x80) { + u &= 0x7f; + tputc('^'); + tputc('['); + } else if(u != '\n' && u != '\r' && u != '\t') { + u ^= 0x40; + tputc('^'); } } - if(len) - tputc(buf, len); + tputc(u); } void @@ -2472,13 +2462,12 @@ tdeftran(char ascii) { void tdectest(char c) { - static char E[UTF_SIZ] = "E"; int x, y; if(c == '8') { /* DEC screen alignment test. */ for(x = 0; x < term.col; ++x) { for(y = 0; y < term.row; ++y) - tsetchar(E, &term.c.attr, x, y); + tsetchar('E', &term.c.attr, x, y); } } } @@ -2506,8 +2495,6 @@ tstrsequence(uchar c) { void tcontrolcode(uchar ascii) { - static char question[UTF_SIZ] = "?"; - switch(ascii) { case '\t': /* HT */ tputtab(1); @@ -2545,7 +2532,7 @@ tcontrolcode(uchar ascii) { term.charset = 1 - (ascii - '\016'); return; case '\032': /* SUB */ - tsetchar(question, &term.c.attr, term.c.x, term.c.y); + tsetchar('?', &term.c.attr, term.c.x, term.c.y); case '\030': /* CAN */ csireset(); break; @@ -2669,28 +2656,21 @@ eschandle(uchar ascii) { } void -tputc(char *c, int len) { - uchar ascii; +tputc(long u) { + char c[UTF_SIZ]; bool control; - long unicodep; - int width; + int width, len; Glyph *gp; - if(len == 1) { + len = utf8encode(u, c); + if((width = wcwidth(u)) == -1) { + memcpy(c, "\357\277\275", 4); /* UTF_INVALID */ width = 1; - unicodep = ascii = *c; - } else { - utf8decode(c, &unicodep, UTF_SIZ); - if ((width = wcwidth(unicodep)) == -1) { - c = "\357\277\275"; /* UTF_INVALID */ - width = 1; - } - ascii = unicodep; } if(IS_SET(MODE_PRINT)) tprinter(c, len); - control = ISCONTROL(unicodep); + control = ISCONTROL(u); /* * STR sequence must be checked before anything else @@ -2699,10 +2679,8 @@ tputc(char *c, int len) { * character. */ if(term.esc & ESC_STR) { - if(len == 1 && - (ascii == '\a' || ascii == 030 || - ascii == 032 || ascii == 033 || - ISCONTROLC1(unicodep))) { + if(u == '\a' || u == 030 || u == 032 || u == 033 || + ISCONTROLC1(u)) { term.esc &= ~(ESC_START|ESC_STR); term.esc |= ESC_STR_END; } else if(strescseq.len + len < sizeof(strescseq.buf) - 1) { @@ -2733,15 +2711,15 @@ tputc(char *c, int len) { * they must not cause conflicts with sequences. */ if(control) { - tcontrolcode(ascii); + tcontrolcode(u); /* * control codes are not shown ever */ return; } else if(term.esc & ESC_START) { if(term.esc & ESC_CSI) { - csiescseq.buf[csiescseq.len++] = ascii; - if(BETWEEN(ascii, 0x40, 0x7E) + csiescseq.buf[csiescseq.len++] = u; + if(BETWEEN(u, 0x40, 0x7E) || csiescseq.len >= \ sizeof(csiescseq.buf)-1) { term.esc = 0; @@ -2750,11 +2728,11 @@ tputc(char *c, int len) { } return; } else if(term.esc & ESC_ALTCHARSET) { - tdeftran(ascii); + tdeftran(u); } else if(term.esc & ESC_TEST) { - tdectest(ascii); + tdectest(u); } else { - if (!eschandle(ascii)) + if (!eschandle(u)) return; /* sequence already finished */ } @@ -2783,12 +2761,12 @@ tputc(char *c, int len) { gp = &term.line[term.c.y][term.c.x]; } - tsetchar(c, &term.c.attr, term.c.x, term.c.y); + tsetchar(u, &term.c.attr, term.c.x, term.c.y); if(width == 2) { gp->mode |= ATTR_WIDE; if(term.c.x+1 < term.col) { - gp[1].c[0] = '\0'; + gp[1].u = '\0'; gp[1].mode = ATTR_WDUMMY; } } @@ -2897,10 +2875,31 @@ sixd_to_16bit(int x) { return x == 0 ? 0 : 0x3737 + 0x2828 * x; } +bool +xloadcolor(int i, const char *name, Color *ncolor) { + XRenderColor color = { .alpha = 0xffff }; + + if(!name) { + if(BETWEEN(i, 16, 255)) { /* 256 color */ + if(i < 6*6*6+16) { /* same colors as xterm */ + color.red = sixd_to_16bit( ((i-16)/36)%6 ); + color.green = sixd_to_16bit( ((i-16)/6) %6 ); + color.blue = sixd_to_16bit( ((i-16)/1) %6 ); + } else { /* greyscale */ + color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16)); + color.green = color.blue = color.red; + } + return XftColorAllocValue(xw.dpy, xw.vis, + xw.cmap, &color, ncolor); + } else + name = colorname[i]; + } + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); +} + void xloadcols(void) { int i; - XRenderColor color = { .alpha = 0xffff }; static bool loaded; Color *cp; @@ -2909,70 +2908,25 @@ xloadcols(void) { XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); } - /* load colors [0-15] and [256-LEN(colorname)] (config.h) */ - for(i = 0; i < LEN(colorname); i++) { - if(!colorname[i]) - continue; - if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, colorname[i], &dc.col[i])) { - die("Could not allocate color '%s'\n", colorname[i]); + for(i = 0; i < LEN(dc.col); i++) + if(!xloadcolor(i, NULL, &dc.col[i])) { + if(colorname[i]) + die("Could not allocate color '%s'\n", colorname[i]); + else + die("Could not allocate color %d\n", i); } - } - - /* load colors [16-231] ; same colors as xterm */ - for(i = 16; i < 6*6*6+16; i++) { - color.red = sixd_to_16bit( ((i-16)/36)%6 ); - color.green = sixd_to_16bit( ((i-16)/6) %6 ); - color.blue = sixd_to_16bit( ((i-16)/1) %6 ); - if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) - die("Could not allocate color %d\n", i); - } - - /* load colors [232-255] ; grayscale */ - for(; i < 256; i++) { - color.red = color.green = color.blue = 0x0808 + 0x0a0a * (i-(6*6*6+16)); - if(!XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, &dc.col[i])) - die("Could not allocate color %d\n", i); - } loaded = true; } int xsetcolorname(int x, const char *name) { - XRenderColor color = { .alpha = 0xffff }; Color ncolor; - if(!BETWEEN(x, 0, LEN(colorname))) + if(!BETWEEN(x, 0, LEN(dc.col))) return 1; - if(!name) { - if(BETWEEN(x, 16, 16 + 215)) { /* 256 color */ - color.red = sixd_to_16bit( ((x-16)/36)%6 ); - color.green = sixd_to_16bit( ((x-16)/6) %6 ); - color.blue = sixd_to_16bit( ((x-16)/1) %6 ); - if(!XftColorAllocValue(xw.dpy, xw.vis, - xw.cmap, &color, &ncolor)) { - return 1; - } - - XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); - dc.col[x] = ncolor; - return 0; - } else if(BETWEEN(x, 16 + 216, 255)) { /* greyscale */ - color.red = color.green = color.blue = \ - 0x0808 + 0x0a0a * (x - (16 + 216)); - if(!XftColorAllocValue(xw.dpy, xw.vis, - xw.cmap, &color, &ncolor)) { - return 1; - } - XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); - dc.col[x] = ncolor; - return 0; - } else { /* system colors */ - name = colorname[x]; - } - } - if(!XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, &ncolor)) + if(!xloadcolor(x, name, &ncolor)) return 1; XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); @@ -3575,11 +3529,20 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { XftDrawSetClip(xw.draw, 0); } +void +xdrawglyph(Glyph g, int x, int y) { + static char buf[UTF_SIZ]; + size_t len = utf8encode(g.u, buf); + int width = g.mode & ATTR_WIDE ? 2 : 1; + + xdraws(buf, g, x, y, width, len); +} + void xdrawcursor(void) { static int oldx = 0, oldy = 0; - int sl, width, curx; - Glyph g = {{' '}, ATTR_NULL, defaultbg, defaultcs}; + int curx; + Glyph g = {' ', ATTR_NULL, defaultbg, defaultcs}; LIMIT(oldx, 0, term.col-1); LIMIT(oldy, 0, term.row-1); @@ -3592,13 +3555,10 @@ xdrawcursor(void) { if(term.line[term.c.y][curx].mode & ATTR_WDUMMY) curx--; - memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); + g.u = term.line[term.c.y][term.c.x].u; /* remove the old cursor */ - sl = utf8len(term.line[oldy][oldx].c); - width = (term.line[oldy][oldx].mode & ATTR_WIDE)? 2 : 1; - xdraws(term.line[oldy][oldx].c, term.line[oldy][oldx], oldx, - oldy, width, sl); + xdrawglyph(term.line[oldy][oldx], oldx, oldy); if(IS_SET(MODE_HIDE)) return; @@ -3615,10 +3575,8 @@ xdrawcursor(void) { g.bg = defaultfg; } - sl = utf8len(g.c); - width = (term.line[term.c.y][curx].mode & ATTR_WIDE)\ - ? 2 : 1; - xdraws(g.c, g, term.c.x, term.c.y, width, sl); + g.mode |= term.line[term.c.y][curx].mode & ATTR_WIDE; + xdrawglyph(g, term.c.x, term.c.y); break; case 3: /* Blinking Underline */ case 4: /* Steady Underline */ @@ -3691,11 +3649,10 @@ draw(void) { void drawregion(int x1, int y1, int x2, int y2) { - int ic, ib, x, y, ox, sl; + int ic, ib, x, y, ox; Glyph base, new; char buf[DRAW_BUF_SIZ]; bool ena_sel = sel.ob.x != -1 && sel.alt == IS_SET(MODE_ALTSCREEN); - long unicodep; if(!(xw.state & WIN_VISIBLE)) return; @@ -3724,9 +3681,7 @@ drawregion(int x1, int y1, int x2, int y2) { base = new; } - sl = utf8decode(new.c, &unicodep, UTF_SIZ); - memcpy(buf+ib, new.c, sl); - ib += sl; + ib += utf8encode(new.u, buf+ib); ic += (new.mode & ATTR_WIDE)? 2 : 1; } if(ib > 0) @@ -3872,7 +3827,7 @@ kpress(XEvent *ev) { if(IS_SET(MODE_8BIT)) { if(*buf < 0177) { c = *buf | 0x80; - len = utf8encode(c, buf, UTF_SIZ); + len = utf8encode(c, buf); } } else { buf[1] = buf[0];