shithub: drawterm

Download patch

ref: 8de603bff116425d9a0943f97898d565a82311a8
parent: 164f93080280163b66fda88ddf15dbd6e74b9443
author: David du Colombier <[email protected]>
date: Wed Jun 17 18:40:15 EDT 2015

gui-win32: fix encoding and decoding of clipboard strings

On Windows, the clipboard strings are encoded in UTF-16.
However, Drawterm considers them as Rune. It used to work
when a Rune was a short, but a Rune is now a int.
The solution is to implement Rune16 functions to
handle UTF-16 strings.

The Rune16 functions were written by Charles Forsyth
as part of Inferno. Balaji Srinivasa integrated them
into Drawterm.

--- a/gui-win32/Makefile
+++ b/gui-win32/Makefile
@@ -7,7 +7,8 @@
 	cload.$O\
 	draw.$O\
 	load.$O\
-	screen.$O
+	screen.$O\
+	r16.$O
 
 default: $(LIB)
 $(LIB): $(OFILES)
--- /dev/null
+++ b/gui-win32/r16.c
@@ -1,0 +1,168 @@
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+
+#include <u.h>
+#include <libc.h>
+#include "r16.h"
+
+#define Bit(i) (7-(i))
+/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */
+#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF)
+/* 0000 0000 0000 0111 1111 1111 */
+#define	RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1)
+
+enum
+{
+	Bitx	= Bit(1),
+
+	Tx	= T(1),			/* 1000 0000 */
+	Rune1 = (1<<(Bit(0)+0*Bitx))-1,	/* 0000 0000 0000 0000 0111 1111 */
+
+	Maskx	= (1<<Bitx)-1,		/* 0011 1111 */
+	Testx	= Maskx ^ 0xFF,		/* 1100 0000 */
+
+	SurrogateMin	= 0xD800,
+	SurrogateMax	= 0xDFFF,
+
+	Bad	= Runeerror,
+};
+
+Rune16*
+runes16dup(Rune16 *r)
+{
+	int n;
+	Rune16 *s;
+
+	n = runes16len(r) + 1;
+	s = malloc(n * sizeof(Rune16));
+	memmove(s, r, n * sizeof(Rune16));
+	return s;
+}
+
+int
+runes16len(Rune16 *r)
+{
+	int n;
+
+	n = 0;
+	while(*r++ != 0)
+		n++;
+	return n;
+}
+
+char*
+runes16toutf(char *p, Rune16 *r, int nc)
+{
+	char *op, *ep;
+	int n, c;
+	Rune rc;
+
+	op = p;
+	ep = p + nc;
+	while(c = *r++) {
+		n = 1;
+		if(c >= Runeself)
+			n = runelen(c);
+		if(p + n >= ep)
+			break;
+		rc = c;
+		if(c < Runeself)
+			*p++ = c;
+		else
+			p += runetochar(p, &rc);
+	}
+	*p = '\0';
+	return op;
+}
+
+int
+rune16nlen(Rune16 *r, int nrune)
+{
+	int nb, i;
+	Rune c;
+
+	nb = 0;
+	while(nrune--) {
+		c = *r++;
+		if(c <= Rune1){
+			nb++;
+		} else {
+			for(i = 2; i < UTFmax + 1; i++)
+				if(c <= RuneX(i) || i == UTFmax){
+					nb += i;
+					break;
+				}
+		}
+	}
+	return nb;
+}
+
+Rune16*
+utftorunes16(Rune16 *r, char *p, int nc)
+{
+	Rune16 *or, *er;
+	Rune rc;
+
+	or = r;
+	er = r + nc;
+	while(*p != '\0' && r + 1 < er){
+		p += chartorune(&rc, p);
+		*r++ = rc;	/* we'll ignore surrogate pairs */
+	}
+	*r = '\0';
+	return or;
+}
+
+int
+runes16cmp(Rune16 *s1, Rune16 *s2)
+{
+	Rune16 r1, r2;
+
+	for(;;) {
+		r1 = *s1++;
+		r2 = *s2++;
+		if(r1 != r2) {
+			if(r1 > r2)
+				return 1;
+			return -1;
+		}
+		if(r1 == 0)
+			return 0;
+	}
+}
+
+wchar_t *
+widen(char *s)
+{
+	int n;
+	wchar_t *ws;
+
+	n = utflen(s) + 1;
+	ws = smalloc(n*sizeof(wchar_t));
+	utftorunes16(ws, s, n);
+	return ws;
+}
+
+
+char *
+narrowen(wchar_t *ws)
+{
+	char *s;
+	int n;
+
+	n = widebytes(ws);
+	s = smalloc(n);
+	runes16toutf(s, ws, n);
+	return s;
+}
+
+
+int
+widebytes(wchar_t *ws)
+{
+	int n = 0;
+
+	while (*ws)
+		n += runelen(*ws++);
+	return n+1;
+}
--- /dev/null
+++ b/gui-win32/r16.h
@@ -1,0 +1,11 @@
+typedef unsigned short Rune16;
+
+wchar_t	*widen(char *s);
+char		*narrowen(wchar_t *ws);
+int		widebytes(wchar_t *ws);
+int		runes16len(Rune16*);
+int		rune16nlen(Rune16*, int);
+Rune16*	runes16dup(Rune16*);
+Rune16*	utftorunes16(Rune16*, char*, int);
+char*	runes16toutf(char*, Rune16*, int);
+int		runes16cmp(Rune16*, Rune16*);
--- a/gui-win32/screen.c
+++ b/gui-win32/screen.c
@@ -14,6 +14,7 @@
 #include <memdraw.h>
 #include "screen.h"
 #include "keyboard.h"
+#include "r16.h"
 
 Memimage	*gscreen;
 Screeninfo	screen;
@@ -544,14 +545,14 @@
 uchar*
 clipreadunicode(HANDLE h)
 {
-	Rune *p;
+	Rune16 *p;
 	int n;
 	uchar *q;
-	
+
 	p = GlobalLock(h);
-	n = wstrutflen(p)+1;
+	n = rune16nlen(p, runes16len(p)+1);
 	q = malloc(n);
-	wstrtoutf(q, p, n);
+	runes16toutf(q, p, n);
 	GlobalUnlock(h);
 
 	return q;
@@ -598,7 +599,7 @@
 {
 	HANDLE h;
 	char *p, *e;
-	Rune *rp;
+	Rune16 *rp;
 	int n = strlen(buf);
 
 	if(!OpenClipboard(window)) {
@@ -616,11 +617,7 @@
 	if(h == NULL)
 		panic("out of memory");
 	rp = GlobalLock(h);
-	p = buf;
-	e = p+n;
-	while(p<e)
-		p += chartorune(rp++, p);
-	*rp = 0;
+	utftorunes16(rp, buf, n+1);
 	GlobalUnlock(h);
 
 	SetClipboardData(CF_UNICODETEXT, h);
--- a/gui-win32/wstrtoutf.c
+++ /dev/null
@@ -1,35 +1,0 @@
-#include <u.h>
-#include <libc.h>
-
-int
-wstrutflen(Rune *s)
-{
-	int n;
-	
-	for(n=0; *s; n+=runelen(*s),s++)
-		;
-	return n;
-}
-
-int
-wstrtoutf(char *s, Rune *t, int n)
-{
-	int i;
-	char *s0;
-
-	s0 = s;
-	if(n <= 0)
-		return wstrutflen(t)+1;
-	while(*t) {
-		if(n < UTFmax+1 && n < runelen(*t)+1) {
-			*s = 0;
-			return i+wstrutflen(t)+1;
-		}
-		i = runetochar(s, t);
-		s += i;
-		n -= i;
-		t++;
-	}
-	*s = 0;
-	return s-s0;
-}