X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=st.c;h=64384cd4747068314db528440b51c63911b679bb;hb=68d97457ecf044bda62a37dd6158bbba4e28d7fe;hp=69b249162b84d95bca15e65f2886f806cc5ebe93;hpb=71328cbcdc88f4fdfbb62d8c0324938e245c8971;p=st.git diff --git a/st.c b/st.c index 69b2491..64384cd 100644 --- a/st.c +++ b/st.c @@ -36,10 +36,6 @@ char *argv0; #define Glyph Glyph_ #define Font Font_ -#define Draw XftDraw * -#define Colour XftColor -#define Colourmap Colormap -#define Rectangle XRectangle #if defined(__linux) #include @@ -55,6 +51,7 @@ char *argv0; #define XEMBED_FOCUS_OUT 5 /* Arbitrary sizes */ +#define UTF_INVALID 0xFFFD #define UTF_SIZ 4 #define ESC_BUF_SIZ (128*UTF_SIZ) #define ESC_ARG_SIZ 16 @@ -68,10 +65,9 @@ char *argv0; #define REDRAW_TIMEOUT (80*1000) /* 80 ms */ /* macros */ -#define SERRNO strerror(errno) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) < (b) ? (b) : (a)) -#define LEN(a) (sizeof(a) / sizeof(a[0])) +#define LEN(a) (sizeof(a) / sizeof(a)[0]) #define DEFAULT(a, b) (a) = (a) ? (a) : (b) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x) @@ -79,6 +75,7 @@ char *argv0; #define IS_SET(flag) ((term.mode & (flag)) != 0) #define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_usec-t2.tv_usec)/1000) #define CEIL(x) (((x) != (int) (x)) ? (x) + 1 : (x)) +#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) #define IS_TRUECOL(x) (1 << 24 & (x)) @@ -179,6 +176,10 @@ typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned short ushort; +typedef XftDraw *Draw; +typedef XftColor Colour; +typedef Colormap Colourmap; + typedef struct { char c[UTF_SIZ]; /* character code */ ushort mode; /* attribute flags */ @@ -359,7 +360,7 @@ static void strparse(void); static void strreset(void); static int tattrset(int); -static void tprinter(char *s, size_t len); +static void tprinter(char *, size_t); static void tdumpsel(void); static void tdumpline(int); static void tdump(void); @@ -370,7 +371,7 @@ static void tdeleteline(int); static void tinsertblank(int); static void tinsertblankline(int); static void tmoveto(int, int); -static void tmoveato(int x, int y); +static void tmoveato(int, int); static void tnew(int, int); static void tnewline(int); static void tputtab(bool); @@ -379,7 +380,7 @@ static void treset(void); static int tresize(int, int); static void tscrollup(int, int); static void tscrolldown(int, int); -static void tsetattr(int*, int); +static void tsetattr(int *, int); static void tsetchar(char *, Glyph *, int, int); static void tsetscroll(int, int); static void tswapscreen(void); @@ -412,9 +413,9 @@ static void xsettitle(char *); static void xresettitle(void); static void xsetpointermotion(int); static void xseturgency(int); -static void xsetsel(char*); +static void xsetsel(char *); static void xtermclear(int, int, int, int); -static void xunloadfont(Font *f); +static void xunloadfont(Font *); static void xunloadfonts(void); static void xresize(int, int); @@ -442,15 +443,17 @@ static void selcopy(void); static void selscroll(int, int); static void selsnap(int, int *, int *, int); -static int utf8decode(char *, long *); -static int utf8encode(long *, char *); -static int utf8size(char *); -static int isfullutf8(char *, int); +static size_t utf8decode(char *, long *, size_t); +static long utf8decodebyte(char, size_t *); +static size_t utf8encode(long, char *, size_t); +static char utf8encodebyte(long, size_t); +static size_t utf8len(char *); +static size_t utf8validate(long *, size_t); static ssize_t xwrite(int, char *, size_t); static void *xmalloc(size_t); static void *xrealloc(void *, size_t); -static char *xstrdup(char *s); +static char *xstrdup(char *); static void (*handler[LASTEvent])(XEvent *) = { [KeyPress] = kpress, @@ -490,6 +493,11 @@ static int oldbutton = 3; /* button event on startup: 3 = release */ static char *usedfont = NULL; static double usedfontsize = 0; +static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; + /* Font Ring Cache */ enum { FRC_NORMAL, @@ -549,128 +557,69 @@ xstrdup(char *s) { return p; } -int -utf8decode(char *s, long *u) { - uchar c; - int i, n, rtn; - - rtn = 1; - c = *s; - if(~c & 0x80) { /* 0xxxxxxx */ - *u = c; - return rtn; - } else if((c & 0xE0) == 0xC0) { /* 110xxxxx */ - *u = c & 0x1F; - n = 1; - } else if((c & 0xF0) == 0xE0) { /* 1110xxxx */ - *u = c & 0x0F; - n = 2; - } else if((c & 0xF8) == 0xF0) { /* 11110xxx */ - *u = c & 0x07; - n = 3; - } else { - goto invalid; - } - - for(i = n, ++s; i > 0; --i, ++rtn, ++s) { - c = *s; - if((c & 0xC0) != 0x80) /* 10xxxxxx */ - goto invalid; - *u <<= 6; - *u |= c & 0x3F; - } - - if((n == 1 && *u < 0x80) || - (n == 2 && *u < 0x800) || - (n == 3 && *u < 0x10000) || - (*u >= 0xD800 && *u <= 0xDFFF)) { - goto invalid; - } - - return rtn; -invalid: - *u = 0xFFFD; +size_t +utf8decode(char *c, long *u, size_t clen) { + size_t i, j, len, type; + long udecoded; - return rtn; -} - -int -utf8encode(long *u, char *s) { - uchar *sp; - ulong uc; - int i, n; - - sp = (uchar *)s; - uc = *u; - if(uc < 0x80) { - *sp = uc; /* 0xxxxxxx */ + *u = UTF_INVALID; + if(!clen) + return 0; + udecoded = utf8decodebyte(c[0], &len); + if(!BETWEEN(len, 1, UTF_SIZ)) return 1; - } else if(*u < 0x800) { - *sp = (uc >> 6) | 0xC0; /* 110xxxxx */ - n = 1; - } else if(uc < 0x10000) { - *sp = (uc >> 12) | 0xE0; /* 1110xxxx */ - n = 2; - } else if(uc <= 0x10FFFF) { - *sp = (uc >> 18) | 0xF0; /* 11110xxx */ - n = 3; - } else { - goto invalid; + for(i = 1, j = 1; i < clen && j < len; ++i, ++j) { + udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type); + if(type != 0) + return j; } + if(j < len) + return 0; + *u = udecoded; + utf8validate(u, len); + return len; +} - for(i=n,++sp; i>0; --i,++sp) - *sp = ((uc >> 6*(i-1)) & 0x3F) | 0x80; /* 10xxxxxx */ - - return n+1; -invalid: - /* U+FFFD */ - *s++ = '\xEF'; - *s++ = '\xBF'; - *s = '\xBD'; - - return 3; +long +utf8decodebyte(char c, size_t *i) { + for(*i = 0; *i < LEN(utfmask); ++(*i)) + if(((uchar)c & utfmask[*i]) == utfbyte[*i]) + return (uchar)c & ~utfmask[*i]; + return 0; } -/* use this if your buffer is less than UTF_SIZ, it returns 1 if you can decode - UTF-8 otherwise return 0 */ -int -isfullutf8(char *s, int b) { - uchar *c1, *c2, *c3; +size_t +utf8encode(long u, char *c, size_t clen) { + size_t len, i; - c1 = (uchar *)s; - c2 = (uchar *)++s; - c3 = (uchar *)++s; - if(b < 1) { - return 0; - } else if((*c1 & 0xE0) == 0xC0 && b == 1) { + len = utf8validate(&u, 0); + if(clen < len) return 0; - } else if((*c1 & 0xF0) == 0xE0 && - ((b == 1) || - ((b == 2) && (*c2 & 0xC0) == 0x80))) { - return 0; - } else if((*c1 & 0xF8) == 0xF0 && - ((b == 1) || - ((b == 2) && (*c2 & 0xC0) == 0x80) || - ((b == 3) && (*c2 & 0xC0) == 0x80 && (*c3 & 0xC0) == 0x80))) { - return 0; - } else { - return 1; + for(i = len - 1; i != 0; --i) { + c[i] = utf8encodebyte(u, 0); + u >>= 6; } + c[0] = utf8encodebyte(u, len); + return len; } -int -utf8size(char *s) { - uchar c = *s; +char +utf8encodebyte(long u, size_t i) { + return utfbyte[i] | (u & ~utfmask[i]); +} - if(~c & 0x80) { - return 1; - } else if((c & 0xE0) == 0xC0) { - return 2; - } else if((c & 0xF0) == 0xE0) { - return 3; - } else { - return 4; - } +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)) + *u = UTF_INVALID; + for(i = 1; *u > utfmax[i]; ++i) + ; + return i; } static void @@ -984,7 +933,7 @@ getsel(void) { if(!selected(x, y) || (gp->mode & ATTR_WDUMMY)) continue; - size = utf8size(gp->c); + size = utf8len(gp->c); memcpy(ptr, gp->c, size); ptr += size; } @@ -1232,7 +1181,7 @@ sigchld(int a) { int stat = 0; if(waitpid(pid, &stat, 0) < 0) - die("Waiting for pid %hd failed: %s\n", pid, SERRNO); + die("Waiting for pid %hd failed: %s\n", pid, strerror(errno)); if(WIFEXITED(stat)) { exit(WEXITSTATUS(stat)); @@ -1248,7 +1197,7 @@ ttynew(void) { /* seems to work fine on linux, openbsd and freebsd */ if(openpty(&m, &s, NULL, NULL, &w) < 0) - die("openpty failed: %s\n", SERRNO); + die("openpty failed: %s\n", strerror(errno)); switch(pid = fork()) { case -1: @@ -1260,7 +1209,7 @@ ttynew(void) { dup2(s, STDOUT_FILENO); dup2(s, STDERR_FILENO); if(ioctl(s, TIOCSCTTY, NULL) < 0) - die("ioctl TIOCSCTTY failed: %s\n", SERRNO); + die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); close(s); close(m); execsh(); @@ -1298,19 +1247,18 @@ ttyread(void) { char *ptr; char s[UTF_SIZ]; int charsize; /* size of utf8 char in bytes */ - long utf8c; + long unicodep; int ret; /* append read bytes to unprocessed bytes */ if((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) - die("Couldn't read from shell: %s\n", SERRNO); + die("Couldn't read from shell: %s\n", strerror(errno)); /* process every complete utf8 char */ buflen += ret; ptr = buf; - while(buflen >= UTF_SIZ || isfullutf8(ptr,buflen)) { - charsize = utf8decode(ptr, &utf8c); - utf8encode(&utf8c, s); + while((charsize = utf8decode(ptr, &unicodep, buflen))) { + utf8encode(unicodep, s, UTF_SIZ); tputc(s, charsize); ptr += charsize; buflen -= charsize; @@ -1323,7 +1271,7 @@ ttyread(void) { void ttywrite(const char *s, size_t n) { if(write(cmdfd, s, n) == -1) - die("write error on tty: %s\n", SERRNO); + die("write error on tty: %s\n", strerror(errno)); } void @@ -1342,7 +1290,7 @@ ttyresize(void) { w.ws_xpixel = xw.tw; w.ws_ypixel = xw.th; if(ioctl(cmdfd, TIOCSWINSZ, &w) < 0) - fprintf(stderr, "Couldn't set window size: %s\n", SERRNO); + fprintf(stderr, "Couldn't set window size: %s\n", strerror(errno)); } int @@ -1680,18 +1628,14 @@ tinsertblank(int n) { void tinsertblankline(int n) { - if(term.c.y < term.top || term.c.y > term.bot) - return; - - tscrolldown(term.c.y, n); + if(BETWEEN(term.c.y, term.top, term.bot)) + tscrolldown(term.c.y, n); } void tdeleteline(int n) { - if(term.c.y < term.top || term.c.y > term.bot) - return; - - tscrollup(term.c.y, n); + if(BETWEEN(term.c.y, term.top, term.bot)) + tscrollup(term.c.y, n); } int32_t @@ -1837,8 +1781,6 @@ tsetscroll(int t, int b) { term.bot = b; } -#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit))) - void tsetmode(bool priv, bool set, int *args, int narg) { int *lim, mode; @@ -1907,7 +1849,10 @@ tsetmode(bool priv, bool set, int *args, int narg) { MODBIT(term.mode, set, MODE_8BIT); break; case 1049: /* swap screen & set/restore cursor as xterm */ + if (!allowaltscreen) + break; tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD); + /* FALLTHRU */ case 47: /* swap screen */ case 1047: if (!allowaltscreen) @@ -2311,13 +2256,13 @@ printsel(const Arg *arg) { } void -tdumpsel(void) -{ +tdumpsel(void) { char *ptr; - ptr = getsel(); - tprinter(ptr, strlen(ptr)); - free(ptr); + if((ptr = getsel())) { + tprinter(ptr, strlen(ptr)); + free(ptr); + } } void @@ -2366,10 +2311,7 @@ techo(char *buf, int len) { for(; len > 0; buf++, len--) { char c = *buf; - if(c == '\033') { /* escape */ - tputc("^", 1); - tputc("[", 1); - } else if(c < '\x20') { /* control code */ + if(c < '\x20') { /* control code */ if(c != '\n' && c != '\r' && c != '\t') { c |= '\x40'; tputc("^", 1); @@ -2404,24 +2346,23 @@ tdeftran(char ascii) { void tselcs(void) { - if (term.trantbl[term.charset] == CS_GRAPHIC0) - term.c.attr.mode |= ATTR_GFX; - else - term.c.attr.mode &= ~ATTR_GFX; + MODBIT(term.c.attr.mode, + term.trantbl[term.charset] == CS_GRAPHIC0, + ATTR_GFX); } void tputc(char *c, int len) { uchar ascii = *c; bool control = ascii < '\x20' || ascii == 0177; - long u8char; + long unicodep; int width; if(len == 1) { width = 1; } else { - utf8decode(c, &u8char); - width = wcwidth(u8char); + utf8decode(c, &unicodep, UTF_SIZ); + width = wcwidth(unicodep); } if(IS_SET(MODE_PRINT)) @@ -3140,7 +3081,7 @@ xinit(void) { xresettitle(); XMapWindow(xw.dpy, xw.win); xhints(); - XSync(xw.dpy, 0); + XSync(xw.dpy, False); } void @@ -3150,7 +3091,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { int frcflags; int u8fl, u8fblen, u8cblen, doesexist; char *u8c, *u8fs; - long u8char; + long unicodep; Font *font = &dc.font; FcResult fcres; FcPattern *fcpattern, *fontpattern; @@ -3158,7 +3099,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { FcCharSet *fccharset; Colour *fg, *bg, *temp, revfg, revbg, truefg, truebg; XRenderColor colfg, colbg; - Rectangle r; + XRectangle r; int oneatatime; frcflags = FRC_NORMAL; @@ -3293,11 +3234,11 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { oneatatime = font->width != xw.cw; for(;;) { u8c = s; - u8cblen = utf8decode(s, &u8char); + u8cblen = utf8decode(s, &unicodep, UTF_SIZ); s += u8cblen; bytelen -= u8cblen; - doesexist = XftCharExists(xw.dpy, font->match, u8char); + doesexist = XftCharExists(xw.dpy, font->match, unicodep); if(oneatatime || !doesexist || bytelen <= 0) { if(oneatatime || bytelen <= 0) { if(doesexist) { @@ -3329,7 +3270,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { /* Search the font cache. */ for(i = 0; i < frclen; i++) { - if(XftCharExists(xw.dpy, frc[i].font, u8char) + if(XftCharExists(xw.dpy, frc[i].font, unicodep) && frc[i].flags == frcflags) { break; } @@ -3351,7 +3292,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { fcpattern = FcPatternDuplicate(font->pattern); fccharset = FcCharSetCreate(); - FcCharSetAddChar(fccharset, u8char); + FcCharSetAddChar(fccharset, unicodep); FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); FcPatternAddBool(fcpattern, FC_SCALABLE, @@ -3387,7 +3328,7 @@ xdraws(char *s, Glyph base, int x, int y, int charlen, int bytelen) { xp, winy + frc[i].font->ascent, (FcChar8 *)u8c, u8cblen); - xp += xw.cw * wcwidth(u8char); + xp += xw.cw * wcwidth(unicodep); } /* @@ -3430,7 +3371,7 @@ xdrawcursor(void) { memcpy(g.c, term.line[term.c.y][term.c.x].c, UTF_SIZ); /* remove the old cursor */ - sl = utf8size(term.line[oldy][oldx].c); + 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); @@ -3444,7 +3385,7 @@ xdrawcursor(void) { g.bg = defaultfg; } - sl = utf8size(g.c); + 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); @@ -3491,7 +3432,6 @@ void redraw(int timeout) { struct timespec tv = {0, timeout * 1000}; - tfulldirt(); draw(); if(timeout > 0) { @@ -3516,7 +3456,7 @@ drawregion(int x1, int y1, int x2, int y2) { Glyph base, new; char buf[DRAW_BUF_SIZ]; bool ena_sel = sel.ob.x != -1; - long u8char; + long unicodep; if(sel.alt ^ IS_SET(MODE_ALTSCREEN)) ena_sel = 0; @@ -3548,7 +3488,7 @@ drawregion(int x1, int y1, int x2, int y2) { base = new; } - sl = utf8decode(new.c, &u8char); + sl = utf8decode(new.c, &unicodep, UTF_SIZ); memcpy(buf+ib, new.c, sl); ib += sl; ic += (new.mode & ATTR_WIDE)? 2 : 1; @@ -3707,7 +3647,7 @@ kpress(XEvent *ev) { if(IS_SET(MODE_8BIT)) { if(*buf < 0177) { c = *buf | 0x80; - len = utf8encode(&c, buf); + len = utf8encode(c, buf, UTF_SIZ); } } else { buf[1] = buf[0]; @@ -3789,8 +3729,8 @@ run(void) { else cresize(xw.fw, xw.fh); - gettimeofday(&lastblink, NULL); gettimeofday(&last, NULL); + lastblink = last; for(xev = actionfps;;) { long deltatime; @@ -3802,7 +3742,7 @@ run(void) { if(select(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv) < 0) { if(errno == EINTR) continue; - die("select failed: %s\n", SERRNO); + die("select failed: %s\n", strerror(errno)); } if(FD_ISSET(cmdfd, &rfd)) { ttyread(); @@ -3825,7 +3765,7 @@ run(void) { if(blinktimeout && TIMEDIFF(now, lastblink) > blinktimeout) { tsetdirtattr(ATTR_BLINK); term.mode ^= MODE_BLINK; - gettimeofday(&lastblink, NULL); + lastblink = now; dodraw = 1; } deltatime = TIMEDIFF(now, last); @@ -3870,7 +3810,7 @@ run(void) { void usage(void) { - die("%s " VERSION " (c) 2010-2013 st engineers\n" \ + die("%s " VERSION " (c) 2010-2014 st engineers\n" \ "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]" \ " [-t title] [-w windowid] [-e command ...]\n", argv0); }