+static Selection sel;
+static char **opt_cmd = NULL;
+static char *opt_title = NULL;
+static char *opt_class = NULL;
+
+int
+utf8decode(char *s, long *u) {
+ unsigned char c;
+ int i, n, rtn;
+
+ rtn = 1;
+ c = *s;
+ if(~c&B7) { /* 0xxxxxxx */
+ *u = c;
+ return rtn;
+ } else if((c&(B7|B6|B5)) == (B7|B6)) { /* 110xxxxx */
+ *u = c&(B4|B3|B2|B1|B0);
+ n = 1;
+ } else if((c&(B7|B6|B5|B4)) == (B7|B6|B5)) { /* 1110xxxx */
+ *u = c&(B3|B2|B1|B0);
+ n = 2;
+ } else if((c&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4)) { /* 11110xxx */
+ *u = c&(B2|B1|B0);
+ n = 3;
+ } else
+ goto invalid;
+ for(i=n,++s; i>0; --i,++rtn,++s) {
+ c = *s;
+ if((c&(B7|B6)) != B7) /* 10xxxxxx */
+ goto invalid;
+ *u <<= 6;
+ *u |= c&(B5|B4|B3|B2|B1|B0);
+ }
+ if((n == 1 && *u < 0x80) ||
+ (n == 2 && *u < 0x800) ||
+ (n == 3 && *u < 0x10000) ||
+ (*u >= 0xD800 && *u <= 0xDFFF))
+ goto invalid;
+ return rtn;
+invalid:
+ *u = 0xFFFD;
+ return rtn;
+}
+
+int
+utf8encode(long *u, char *s) {
+ unsigned char *sp;
+ unsigned long uc;
+ int i, n;
+
+ sp = (unsigned char*) s;
+ uc = *u;
+ if(uc < 0x80) {
+ *sp = uc; /* 0xxxxxxx */
+ return 1;
+ } else if(*u < 0x800) {
+ *sp = (uc >> 6) | (B7|B6); /* 110xxxxx */
+ n = 1;
+ } else if(uc < 0x10000) {
+ *sp = (uc >> 12) | (B7|B6|B5); /* 1110xxxx */
+ n = 2;
+ } else if(uc <= 0x10FFFF) {
+ *sp = (uc >> 18) | (B7|B6|B5|B4); /* 11110xxx */
+ n = 3;
+ } else {
+ goto invalid;
+ }
+ for(i=n,++sp; i>0; --i,++sp)
+ *sp = ((uc >> 6*(i-1)) & (B5|B4|B3|B2|B1|B0)) | B7; /* 10xxxxxx */
+ return n+1;
+invalid:
+ /* U+FFFD */
+ *s++ = '\xEF';
+ *s++ = '\xBF';
+ *s = '\xBD';
+ return 3;
+}
+
+/* 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) {
+ unsigned char *c1, *c2, *c3;
+
+ c1 = (unsigned char *) s;
+ c2 = (unsigned char *) ++s;
+ c3 = (unsigned char *) ++s;
+ if(b < 1)
+ return 0;
+ else if((*c1&(B7|B6|B5)) == (B7|B6) && b == 1)
+ return 0;
+ else if((*c1&(B7|B6|B5|B4)) == (B7|B6|B5) &&
+ ((b == 1) ||
+ ((b == 2) && (*c2&(B7|B6)) == B7)))
+ return 0;
+ else if((*c1&(B7|B6|B5|B4|B3)) == (B7|B6|B5|B4) &&
+ ((b == 1) ||
+ ((b == 2) && (*c2&(B7|B6)) == B7) ||
+ ((b == 3) && (*c2&(B7|B6)) == B7 && (*c3&(B7|B6)) == B7)))
+ return 0;
+ else
+ return 1;
+}
+
+int
+utf8size(char *s) {
+ unsigned char c = *s;
+
+ if(~c&B7)
+ return 1;
+ else if((c&(B7|B6|B5)) == (B7|B6))
+ return 2;
+ else if((c&(B7|B6|B5|B4)) == (B7|B6|B5))
+ return 3;
+ else
+ return 4;
+}
+
+void
+selinit(void) {
+ sel.tclick1.tv_sec = 0;
+ sel.tclick1.tv_usec = 0;
+ sel.mode = 0;
+ sel.bx = -1;
+ sel.clip = NULL;
+ sel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0);
+ if(sel.xtarget == None)
+ sel.xtarget = XA_STRING;
+}
+
+static inline int
+selected(int x, int y) {
+ if(sel.ey == y && sel.by == y) {
+ int bx = MIN(sel.bx, sel.ex);
+ int ex = MAX(sel.bx, sel.ex);
+ return BETWEEN(x, bx, ex);
+ }
+ return ((sel.b.y < y&&y < sel.e.y) || (y==sel.e.y && x<=sel.e.x))
+ || (y==sel.b.y && x>=sel.b.x && (x<=sel.e.x || sel.b.y!=sel.e.y));
+}
+
+void
+getbuttoninfo(XEvent *e, int *b, int *x, int *y) {
+ if(b)
+ *b = e->xbutton.button;
+
+ *x = (e->xbutton.x - BORDER)/xw.cw;
+ *y = (e->xbutton.y - BORDER)/xw.ch;
+ sel.b.x = sel.by < sel.ey ? sel.bx : sel.ex;
+ sel.b.y = MIN(sel.by, sel.ey);
+ sel.e.x = sel.by < sel.ey ? sel.ex : sel.bx;
+ sel.e.y = MAX(sel.by, sel.ey);
+}
+
+void
+bpress(XEvent *e) {
+ sel.mode = 1;
+ sel.ex = sel.bx = (e->xbutton.x - BORDER)/xw.cw;
+ sel.ey = sel.by = (e->xbutton.y - BORDER)/xw.ch;
+}
+
+void
+selcopy(void) {
+ char *str, *ptr;
+ int x, y, sz, sl, ls = 0;
+
+ if(sel.bx == -1)
+ str = NULL;
+ else {
+ sz = (term.col+1) * (sel.e.y-sel.b.y+1) * UTF_SIZ;
+ ptr = str = malloc(sz);
+ for(y = 0; y < term.row; y++) {
+ for(x = 0; x < term.col; x++)
+ if(term.line[y][x].state & GLYPH_SET && (ls = selected(x, y))) {
+ sl = utf8size(term.line[y][x].c);
+ memcpy(ptr, term.line[y][x].c, sl);
+ ptr += sl;
+ }
+ if(ls && y < sel.e.y)
+ *ptr++ = '\n';
+ }
+ *ptr = 0;
+ }
+ xsetsel(str);
+}
+
+void
+selnotify(XEvent *e) {
+ unsigned long nitems;
+ unsigned long ofs, rem;
+ int format;
+ unsigned char *data;
+ Atom type;
+
+ ofs = 0;
+ do {
+ if(XGetWindowProperty(xw.dpy, xw.win, XA_PRIMARY, ofs, BUFSIZ/4,
+ False, AnyPropertyType, &type, &format,
+ &nitems, &rem, &data)) {
+ fprintf(stderr, "Clipboard allocation failed\n");
+ return;
+ }
+ ttywrite((const char *) data, nitems * format / 8);
+ XFree(data);
+ /* number of 32-bit chunks returned */
+ ofs += nitems * format / 32;
+ } while(rem > 0);
+}
+
+void
+selpaste() {
+ XConvertSelection(xw.dpy, XA_PRIMARY, sel.xtarget, XA_PRIMARY, xw.win, CurrentTime);
+}