]> git.armaanb.net Git - st.git/blobdiff - st.c
Do not mark as invalid UTF8 control codes
[st.git] / st.c
diff --git a/st.c b/st.c
index 17e0a65493aeab1b63097b187529a476dc5be13d..35a840b66ef906c50e718ecd2176c98d3dfa8964 100644 (file)
--- a/st.c
+++ b/st.c
@@ -62,26 +62,28 @@ char *argv0;
 #define XK_SWITCH_MOD (1<<13)
 
 /* macros */
-#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 DEFAULT(a, b)     (a) = (a) ? (a) : (b)
-#define BETWEEN(x, a, b)  ((a) <= (x) && (x) <= (b))
-#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) (utf8strchr(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)
-#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + (t1.tv_nsec-t2.tv_nsec)/1E6)
-#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))
-#define TRUERED(x)       (((x) & 0xff0000) >> 8)
-#define TRUEGREEN(x)     (((x) & 0xff00))
-#define TRUEBLUE(x)      (((x) & 0xff) << 8)
+#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 DEFAULT(a, b)          (a) = (a) ? (a) : (b)
+#define BETWEEN(x, a, b)       ((a) <= (x) && (x) <= (b))
+#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)             (utf8strchr(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)
+#define TIMEDIFF(t1, t2)       ((t1.tv_sec-t2.tv_sec)*1000 + \
+                               (t1.tv_nsec-t2.tv_nsec)/1E6)
+#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))
+#define TRUERED(x)             (((x) & 0xff0000) >> 8)
+#define TRUEGREEN(x)           (((x) & 0xff00))
+#define TRUEBLUE(x)            (((x) & 0xff) << 8)
 
 
 enum glyph_attribute {
@@ -559,14 +561,16 @@ ssize_t
 xwrite(int fd, const char *s, size_t len)
 {
        size_t aux = len;
+       ssize_t r;
 
        while (len > 0) {
-               ssize_t r = write(fd, s, len);
+               r = write(fd, s, len);
                if (r < 0)
                        return r;
                len -= r;
                s += r;
        }
+
        return aux;
 }
 
@@ -620,6 +624,7 @@ utf8decode(char *c, Rune *u, size_t clen)
                return 0;
        *u = udecoded;
        utf8validate(u, len);
+
        return len;
 }
 
@@ -629,6 +634,7 @@ 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;
 }
 
@@ -640,11 +646,13 @@ utf8encode(Rune u, char *c)
        len = utf8validate(&u, 0);
        if (len > UTF_SIZ)
                return 0;
+
        for (i = len - 1; i != 0; --i) {
                c[i] = utf8encodebyte(u, 0);
                u >>= 6;
        }
        c[0] = utf8encodebyte(u, len);
+
        return len;
 }
 
@@ -667,6 +675,7 @@ utf8strchr(char *s, Rune u)
                if (r == u)
                        return &(s[i]);
        }
+
        return NULL;
 }
 
@@ -677,6 +686,7 @@ utf8validate(Rune *u, size_t i)
                *u = UTF_INVALID;
        for (i = 1; *u > utfmax[i]; ++i)
                ;
+
        return i;
 }
 
@@ -1044,7 +1054,7 @@ propnotify(XEvent *e)
        if (xpev->state == PropertyNewValue &&
                        (xpev->atom == XA_PRIMARY ||
                         xpev->atom == clipboard)) {
-               slenotify(e);
+               selnotify(e);
        }
 }
 
@@ -1056,6 +1066,8 @@ selnotify(XEvent *e)
        uchar *data, *last, *repl;
        Atom type, incratom, property;
 
+       incratom = XInternAtom(xw.dpy, "INCR", 0);
+
        ofs = 0;
        if (e->type == SelectionNotify) {
                property = e->xselection.property;
@@ -1318,9 +1330,8 @@ execsh(void)
                        die("who are you?\n");
        }
 
-       if (!(sh = getenv("SHELL"))) {
+       if ((sh = getenv("SHELL")) == NULL)
                sh = (pw->pw_shell[0]) ? pw->pw_shell : shell;
-       }
 
        if (opt_cmd)
                prog = opt_cmd[0];
@@ -1478,8 +1489,57 @@ ttyread(void)
 void
 ttywrite(const char *s, size_t n)
 {
-       if (xwrite(cmdfd, s, n) == -1)
-               die("write error on tty: %s\n", strerror(errno));
+       fd_set wfd;
+       struct timespec tv;
+       ssize_t r;
+
+       /*
+        * Remember that we are using a pty, which might be a modem line.
+        * Writing too much will clog the line. That's why we are doing this
+        * dance.
+        * FIXME: Migrate the world to Plan 9.
+        */
+       while (n > 0) {
+               FD_ZERO(&wfd);
+               FD_SET(cmdfd, &wfd);
+               tv.tv_sec = 0;
+               tv.tv_nsec = 0;
+
+               /* Check if we can write. */
+               if (pselect(cmdfd+1, NULL, &wfd, NULL, &tv, NULL) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       die("select failed: %s\n", strerror(errno));
+               }
+               if(!FD_ISSET(cmdfd, &wfd)) {
+                       /* No, then free some buffer space. */
+                       ttyread();
+               } else {
+                       /*
+                        * Only write 256 bytes at maximum. This seems to be a
+                        * reasonable value for a serial line. Bigger values
+                        * might clog the I/O.
+                        */
+                       r = write(cmdfd, s, (n < 256)? n : 256);
+                       if (r < 0) {
+                               die("write error on tty: %s\n",
+                                               strerror(errno));
+                       }
+                       if (r < n) {
+                               /*
+                                * We weren't able to write out everything.
+                                * This means the buffer is getting full
+                                * again. Empty it.
+                                */
+                               ttyread();
+                               n -= r;
+                               s += r;
+                       } else {
+                               /* All bytes have been written. */
+                               break;
+                       }
+               }
+       }
 }
 
 void
@@ -2835,15 +2895,15 @@ tputc(Rune u)
        int width, len;
        Glyph *gp;
 
+       control = ISCONTROL(u);
        len = utf8encode(u, c);
-       if ((width = wcwidth(u)) == -1) {
+       if (!control && (width = wcwidth(u)) == -1) {
                memcpy(c, "\357\277\275", 4); /* UTF_INVALID */
                width = 1;
        }
 
        if (IS_SET(MODE_PRINT))
                tprinter(c, len);
-       control = ISCONTROL(u);
 
        /*
         * STR sequence must be checked before anything else
@@ -3074,6 +3134,7 @@ xloadcolor(int i, const char *name, Color *ncolor)
                } else
                        name = colorname[i];
        }
+
        return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
 }
 
@@ -3113,6 +3174,7 @@ xsetcolorname(int x, const char *name)
 
        XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]);
        dc.col[x] = ncolor;
+
        return 0;
 }
 
@@ -3182,6 +3244,7 @@ xgeommasktogravity(int mask)
        case YNegative:
                return SouthWestGravity;
        }
+
        return SouthEastGravity;
 }
 
@@ -3348,6 +3411,7 @@ xinit(void)
        Cursor cursor;
        Window parent;
        pid_t thispid = getpid();
+       XColor xmousefg, xmousebg;
 
        if (!(xw.dpy = XOpenDisplay(NULL)))
                die("Can't open display\n");
@@ -3420,11 +3484,22 @@ xinit(void)
                die("XCreateIC failed. Could not obtain input method.\n");
 
        /* white cursor, black outline */
-       cursor = XCreateFontCursor(xw.dpy, XC_xterm);
+       cursor = XCreateFontCursor(xw.dpy, mouseshape);
        XDefineCursor(xw.dpy, xw.win, cursor);
-       XRecolorCursor(xw.dpy, cursor,
-               &(XColor){.red = 0xffff, .green = 0xffff, .blue = 0xffff},
-               &(XColor){.red = 0x0000, .green = 0x0000, .blue = 0x0000});
+
+       if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
+               xmousefg.red   = 0xffff;
+               xmousefg.green = 0xffff;
+               xmousefg.blue  = 0xffff;
+       }
+
+       if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) {
+               xmousebg.red   = 0x0000;
+               xmousebg.green = 0x0000;
+               xmousebg.blue  = 0x0000;
+       }
+
+       XRecolorCursor(xw.dpy, cursor, &xmousefg, &xmousebg);
 
        xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
        xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
@@ -4097,9 +4172,9 @@ run(void)
        do {
                XNextEvent(xw.dpy, &ev);
                /*
-                * XFilterEvent is required to be called after you using XOpenIM,
-                * this is not unnecessary.It does not only filter the key event,
-                * but some clientmessage for input method as well.
+                * This XFilterEvent call is required because of XOpenIM. It
+                * does filter out the key event and some client message for
+                * the input method too.
                 */
                if (XFilterEvent(&ev, None))
                        continue;
@@ -4196,9 +4271,11 @@ usage(void)
 {
        die("%s " VERSION " (c) 2010-2015 st engineers\n"
        "usage: st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-       "          [-i] [-t title] [-w windowid] [-e command ...] [command ...]\n"
+       "          [-i] [-t title] [-T title] [-w windowid] [-e command ...]"
+       " [command ...]\n"
        "       st [-a] [-v] [-c class] [-f font] [-g geometry] [-o file]\n"
-       "          [-i] [-t title] [-w windowid] [-l line] [stty_args ...]\n",
+       "          [-i] [-t title] [-T title] [-w windowid] [-l line]"
+       " [stty_args ...]\n",
        argv0);
 }
 
@@ -4239,6 +4316,7 @@ main(int argc, char *argv[])
                opt_line = EARGF(usage());
                break;
        case 't':
+       case 'T':
                opt_title = EARGF(usage());
                break;
        case 'w':
@@ -4265,3 +4343,4 @@ run:
 
        return 0;
 }
+