At last! After much delay, much faffing back and forth, and much
[u/mdw/putty] / ldisc.c
diff --git a/ldisc.c b/ldisc.c
index d569f11..d57e6d1 100644 (file)
--- a/ldisc.c
+++ b/ldisc.c
@@ -23,7 +23,7 @@
 
 static void c_write(Ldisc ldisc, char *buf, int len)
 {
-    from_backend(ldisc->term, 0, buf, len);
+    from_backend(ldisc->frontend, 0, buf, len);
 }
 
 static int plen(Ldisc ldisc, unsigned char c)
@@ -32,13 +32,20 @@ static int plen(Ldisc ldisc, unsigned char c)
        return 1;
     else if (c < 128)
        return 2;                      /* ^x for some x */
+    else if (in_utf(ldisc->term) && c >= 0xC0)
+       return 1;                      /* UTF-8 introducer character
+                                       * (FIXME: combining / wide chars) */
+    else if (in_utf(ldisc->term) && c >= 0x80 && c < 0xC0)
+       return 0;                      /* UTF-8 followup character */
     else
-       return 4;                      /* <XY> for hex XY */
+       return 4;                      /* <XY> hex representation */
 }
 
 static void pwrite(Ldisc ldisc, unsigned char c)
 {
-    if ((c >= 32 && c <= 126) || (c >= 160 && !in_utf(ldisc->term))) {
+    if ((c >= 32 && c <= 126) ||
+       (!in_utf(ldisc->term) && c >= 0xA0) ||
+       (in_utf(ldisc->term) && c >= 0x80)) {
        c_write(ldisc, (char *)&c, 1);
     } else if (c < 128) {
        char cc[2];
@@ -52,6 +59,14 @@ static void pwrite(Ldisc ldisc, unsigned char c)
     }
 }
 
+static int char_start(Ldisc ldisc, unsigned char c)
+{
+    if (in_utf(ldisc->term))
+       return (c < 0x80 || c >= 0xC0);
+    else
+       return 1;
+}
+
 static void bsb(Ldisc ldisc, int n)
 {
     while (n--)
@@ -65,7 +80,7 @@ void *ldisc_create(Config *mycfg, Terminal *term,
                   Backend *back, void *backhandle,
                   void *frontend)
 {
-    Ldisc ldisc = smalloc(sizeof(*ldisc));
+    Ldisc ldisc = snew(struct ldisc_tag);
 
     ldisc->buf = NULL;
     ldisc->buflen = 0;
@@ -137,7 +152,9 @@ void ldisc_send(void *handle, char *buf, int len, int interactive)
                c += KCTRL('@');
            switch (ldisc->quotenext ? ' ' : c) {
                /*
-                * ^h/^?: delete one char and output one BSB
+                * ^h/^?: delete, and output BSBs, to return to
+                * last character boundary (in UTF-8 mode this may
+                * be more than one byte)
                 * ^w: delete, and output BSBs, to return to last
                 * space/nonspace boundary
                 * ^u: delete, and output BSBs, to return to BOL
@@ -153,9 +170,11 @@ void ldisc_send(void *handle, char *buf, int len, int interactive)
              case KCTRL('H'):
              case KCTRL('?'):         /* backspace/delete */
                if (ldisc->buflen > 0) {
-                   if (ECHOING)
-                       bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
-                   ldisc->buflen--;
+                   do {
+                       if (ECHOING)
+                           bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
+                       ldisc->buflen--;
+                   } while (!char_start(ldisc, ldisc->buf[ldisc->buflen]));
                }
                break;
              case CTRL('W'):          /* delete word */
@@ -164,8 +183,8 @@ void ldisc_send(void *handle, char *buf, int len, int interactive)
                        bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1]));
                    ldisc->buflen--;
                    if (ldisc->buflen > 0 &&
-                       isspace(ldisc->buf[ldisc->buflen - 1]) &&
-                       !isspace(ldisc->buf[ldisc->buflen]))
+                       isspace((unsigned char)ldisc->buf[ldisc->buflen-1]) &&
+                       !isspace((unsigned char)ldisc->buf[ldisc->buflen]))
                        break;
                }
                break;
@@ -261,7 +280,7 @@ void ldisc_send(void *handle, char *buf, int len, int interactive)
                 default_case:
                if (ldisc->buflen >= ldisc->bufsiz) {
                    ldisc->bufsiz = ldisc->buflen + 256;
-                   ldisc->buf = srealloc(ldisc->buf, ldisc->bufsiz);
+                   ldisc->buf = sresize(ldisc->buf, ldisc->bufsiz, char);
                }
                ldisc->buf[ldisc->buflen++] = c;
                if (ECHOING)