JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Using strsep and fixing null termination in csiparse.
[st.git] / st.c
diff --git a/st.c b/st.c
index c25f24c..fc9ed70 100644 (file)
--- a/st.c
+++ b/st.c
@@ -1,5 +1,4 @@
 /* See LICENSE for licence details. */
-#define _XOPEN_SOURCE 600
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -25,7 +24,6 @@
 #include <X11/Xutil.h>
 #include <X11/cursorfont.h>
 #include <X11/keysym.h>
-#include <X11/extensions/Xdbe.h>
 #include <X11/Xft/Xft.h>
 #include <fontconfig/fontconfig.h>
 
@@ -267,9 +265,10 @@ typedef struct {
 } Shortcut;
 
 /* function definitions used in config.h */
-static void xzoom(const Arg *);
-static void selpaste(const Arg *);
+static void clippaste(const Arg *);
 static void numlock(const Arg *);
+static void selpaste(const Arg *);
+static void xzoom(const Arg *);
 
 /* Config.h for applying patches and the configuration. */
 #include "config.h"
@@ -302,7 +301,6 @@ static void execsh(void);
 static void sigchld(int);
 static void run(void);
 
-static inline int parse_int(char *);
 static void csidump(void);
 static void csihandle(void);
 static void csiparse(void);
@@ -352,6 +350,7 @@ static void xloadcols(void);
 static int xsetcolorname(int, const char *);
 static int xloadfont(Font *, FcPattern *);
 static void xloadfonts(char *, int);
+static void xsettitle(char *);
 static void xresettitle(void);
 static void xseturgency(int);
 static void xsetsel(char*);
@@ -424,8 +423,6 @@ static char *opt_embed = NULL;
 static char *opt_class = NULL;
 static char *opt_font = NULL;
 
-bool usedbe = False;
-
 static char *usedfont = NULL;
 static int usedfontsize = 0;
 
@@ -798,7 +795,7 @@ selcopy(void) {
                        }
                        /* \n at the end of every selected line except for the last one */
                        if(is_selected && y < sel.e.y)
-                               *ptr++ = '\n';
+                               *ptr++ = '\r';
                }
                *ptr = 0;
        }
@@ -833,7 +830,17 @@ selpaste(const Arg *dummy) {
                        xw.win, CurrentTime);
 }
 
-void selclear(XEvent *e) {
+void
+clippaste(const Arg *dummy) {
+       Atom clipboard;
+
+       clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0);
+       XConvertSelection(xw.dpy, clipboard, sel.xtarget, XA_PRIMARY,
+                       xw.win, CurrentTime);
+}
+
+void
+selclear(XEvent *e) {
        if(sel.bx == -1)
                return;
        sel.bx = -1;
@@ -941,7 +948,7 @@ brelease(XEvent *e) {
 
 void
 bmotion(XEvent *e) {
-       int oldey, oldex;
+       int oldey, oldex, oldsby, oldsey;
 
        if(IS_SET(MODE_MOUSE)) {
                mousereport(e);
@@ -953,10 +960,12 @@ bmotion(XEvent *e) {
 
        oldey = sel.ey;
        oldex = sel.ex;
+       oldsby = sel.b.y;
+       oldsey = sel.e.y;
        getbuttoninfo(e);
 
        if(oldey != sel.ey || oldex != sel.ex) {
-               tsetdirt(sel.b.y, sel.e.y);
+               tsetdirt(MIN(sel.b.y, oldsby), MAX(sel.e.y, oldsey));
        }
 }
 
@@ -1285,27 +1294,30 @@ tnewline(int first_col) {
 
 void
 csiparse(void) {
-       /* int noarg = 1; */
-       char *p = csiescseq.buf;
+       char *p = csiescseq.buf, *np;
+       long int v;
 
        csiescseq.narg = 0;
-       if(*p == '?')
-               csiescseq.priv = 1, p++;
+       if(*p == '?') {
+               csiescseq.priv = 1;
+               p++;
+       }
 
+       csiescseq.buf[csiescseq.len] = '\0';
        while(p < csiescseq.buf+csiescseq.len) {
-               while(isdigit(*p)) {
-                       csiescseq.arg[csiescseq.narg] *= 10;
-                       csiescseq.arg[csiescseq.narg] += *p++ - '0'/*, noarg = 0 */;
-               }
-               if(*p == ';' && csiescseq.narg+1 < ESC_ARG_SIZ) {
-                       csiescseq.narg++, p++;
-               } else {
-                       csiescseq.mode = *p;
-                       csiescseq.narg++;
-
-                       return;
-               }
+               np = NULL;
+               v = strtol(p, &np, 10);
+               if(np == p)
+                       v = 0;
+               if(v == LONG_MAX || v == LONG_MIN)
+                       v = -1;
+               csiescseq.arg[csiescseq.narg++] = v;
+               p = np;
+               if(*p != ';' || csiescseq.narg == ESC_ARG_SIZ)
+                       break;
+               p++;
        }
+       csiescseq.mode = *p;
 }
 
 /* for absolute user moves, when decom is set */
@@ -1857,45 +1869,22 @@ csireset(void) {
        memset(&csiescseq, 0, sizeof(csiescseq));
 }
 
-inline int
-parse_int(char *s) {
-       int x = 0;
-       char c;
-       while(isdigit(c = *s)) {
-               if((INT_MAX - c + '0') / 10 >= x) {
-                       x = x * 10 + c - '0';
-               } else
-                       return -1;
-               s++;
-       }
-       if(*s != '\0')
-               return -1;
-       return x;
-}
-
 void
 strhandle(void) {
        char *p = NULL;
-       int i, j;
-       int narg;
+       int i, j, narg;
 
-       /*
-        * TODO: make this being useful in case of color palette change.
-        */
        strparse();
        narg = strescseq.narg;
 
        switch(strescseq.type) {
        case ']': /* OSC -- Operating System Command */
-               switch(i = parse_int(strescseq.args[0])) {
+               switch(i = atoi(strescseq.args[0])) {
                case 0:
                case 1:
                case 2:
-                       /*
-                        * TODO: Handle special chars in string, like umlauts.
-                        */
                        if(narg > 1)
-                               XStoreName(xw.dpy, xw.win, strescseq.args[2]);
+                               xsettitle(strescseq.args[1]);
                        break;
                case 4: /* color set */
                        if(narg < 3)
@@ -1903,11 +1892,15 @@ strhandle(void) {
                        p = strescseq.args[2];
                        /* fall through */
                case 104: /* color reset, here p = NULL */
-                       j = (narg > 1) ? parse_int(strescseq.args[1]) : -1;
-                       if (!xsetcolorname(j, p))
+                       j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
+                       if (!xsetcolorname(j, p)) {
                                fprintf(stderr, "erresc: invalid color %s\n", p);
-                       else {
-                               redraw(0); /* TODO if defaultbg color is changed, borders are dirty */
+                       } else {
+                               /*
+                                * TODO if defaultbg color is changed, borders
+                                * are dirty
+                                */
+                               redraw(0);
                        }
                        break;
                default:
@@ -1917,7 +1910,7 @@ strhandle(void) {
                }
                break;
        case 'k': /* old title set compatibility */
-               XStoreName(xw.dpy, xw.win, strescseq.buf);
+               xsettitle(strescseq.args[0]);
                break;
        case 'P': /* DSC -- Device Control String */
        case '_': /* APC -- Application Program Command */
@@ -1932,23 +1925,12 @@ strhandle(void) {
 
 void
 strparse(void) {
-       /*
-        * TODO: Implement parsing like for CSI when required.
-        * Format: ESC type cmd ';' arg0 [';' argn] ESC \
-        */
-       int narg = 0;
-       char *start = strescseq.buf, *end = start + strescseq.len;
-       strescseq.args[0] = start;
-       while(start < end && narg < LEN(strescseq.args)) {
-               start = memchr(start, ';', end - start);
-               if(!start)
-                       break;
-               *start++ = '\0';
-               if(start < end) {
-                       strescseq.args[++narg] = start;
-               }
-       }
-       strescseq.narg = narg + 1;
+       char *p = strescseq.buf;
+
+       strescseq.narg = 0;
+       strescseq.buf[strescseq.len] = '\0';
+       while(p && strescseq.narg < STR_ARG_SIZ)
+               strescseq.args[strescseq.narg++] = strsep(&p, ";");
 }
 
 void
@@ -1959,7 +1941,9 @@ strdump(void) {
        printf("ESC%c", strescseq.type);
        for(i = 0; i < strescseq.len; i++) {
                c = strescseq.buf[i] & 0xff;
-               if(isprint(c)) {
+               if(c == '\0') {
+                       return;
+               } else if(isprint(c)) {
                        putchar(c);
                } else if(c == '\n') {
                        printf("(\\n)");
@@ -2047,7 +2031,7 @@ tputc(char *c, int len) {
                        strhandle();
                        break;
                default:
-                       if(strescseq.len + len < sizeof(strescseq.buf)) {
+                       if(strescseq.len + len < sizeof(strescseq.buf) - 1) {
                                memmove(&strescseq.buf[strescseq.len], c, len);
                                strescseq.len += len;
                        } else {
@@ -2123,9 +2107,11 @@ tputc(char *c, int len) {
                if(term.esc & ESC_CSI) {
                        csiescseq.buf[csiescseq.len++] = ascii;
                        if(BETWEEN(ascii, 0x40, 0x7E)
-                                       || csiescseq.len >= ESC_BUF_SIZ) {
+                                       || csiescseq.len >= \
+                                       sizeof(csiescseq.buf)-1) {
                                term.esc = 0;
-                               csiparse(), csihandle();
+                               csiparse();
+                               csihandle();
                        }
                } else if(term.esc & ESC_STR_END) {
                        term.esc = 0;
@@ -2352,13 +2338,11 @@ xresize(int col, int row) {
        xw.tw = MAX(1, col * xw.cw);
        xw.th = MAX(1, row * xw.ch);
 
-       if(!usedbe) {
-               XFreePixmap(xw.dpy, xw.buf);
-               xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
-                               DefaultDepth(xw.dpy, xw.scr));
-               XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
-               XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-       }
+       XFreePixmap(xw.dpy, xw.buf);
+       xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
+                       DefaultDepth(xw.dpy, xw.scr));
+       XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
+       XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 
        XftDrawChange(xw.draw, xw.buf);
 }
@@ -2620,7 +2604,7 @@ xinit(void) {
        XGCValues gcvalues;
        Cursor cursor;
        Window parent;
-       int sw, sh, major, minor;
+       int sw, sh;
 
        if(!(xw.dpy = XOpenDisplay(NULL)))
                die("Can't open display\n");
@@ -2675,26 +2659,14 @@ xinit(void) {
                        | CWColormap,
                        &attrs);
 
-       /* double buffering */
-       /*
-       if(XdbeQueryExtension(xw.dpy, &major, &minor)) {
-               xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win,
-                               XdbeBackground);
-               usedbe = True;
-       } else {
-       */
-               memset(&gcvalues, 0, sizeof(gcvalues));
-               gcvalues.graphics_exposures = False;
-               dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
-                               &gcvalues);
-               xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
-                               DefaultDepth(xw.dpy, xw.scr));
-               XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
-               XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
-               //xw.buf = xw.win;
-       /*
-       }
-       */
+       memset(&gcvalues, 0, sizeof(gcvalues));
+       gcvalues.graphics_exposures = False;
+       dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
+                       &gcvalues);
+       xw.buf = XCreatePixmap(xw.dpy, xw.win, xw.w, xw.h,
+                       DefaultDepth(xw.dpy, xw.scr));
+       XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
+       XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, xw.w, xw.h);
 
        /* Xft rendering context */
        xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
@@ -2985,9 +2957,19 @@ xdrawcursor(void) {
        }
 }
 
+
+void
+xsettitle(char *p) {
+       XTextProperty prop;
+
+       Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+                       &prop);
+       XSetWMName(xw.dpy, xw.win, &prop);
+}
+
 void
 xresettitle(void) {
-       XStoreName(xw.dpy, xw.win, opt_title ? opt_title : "st");
+       xsettitle(opt_title ? opt_title : "st");
 }
 
 void
@@ -3005,16 +2987,12 @@ redraw(int timeout) {
 
 void
 draw(void) {
-       XdbeSwapInfo swpinfo[1] = {{xw.win, XdbeCopied}};
-
        drawregion(0, 0, term.col, term.row);
-       if(usedbe) {
-               XdbeSwapBuffers(xw.dpy, swpinfo, 1);
-       } else {
-               XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
-                               xw.h, 0, 0);
-               XSetForeground(xw.dpy, dc.gc, dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel);
-       }
+       XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, xw.w,
+                       xw.h, 0, 0);
+       XSetForeground(xw.dpy, dc.gc,
+                       dc.col[IS_SET(MODE_REVERSE)?
+                               defaultfg : defaultbg].pixel);
 }
 
 void