ref: 8de603bff116425d9a0943f97898d565a82311a8
parent: 164f93080280163b66fda88ddf15dbd6e74b9443
author: David du Colombier <0intro@gmail.com>
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;
-}