Added local-editing line discipline to make raw backend usable
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 9 Nov 1999 12:05:34 +0000 (12:05 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Tue, 9 Nov 1999 12:05:34 +0000 (12:05 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/putty@287 cda61777-01e9-0310-a592-d414129be87e

Makefile
ldisc.c [new file with mode: 0644]
putty.h
terminal.c
win_res.h
win_res.rc
windlg.c
window.c

index 2f26319..00157ca 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,8 @@ CFLAGS = /nologo /W3 /YX /O2 /Yd /D_WINDOWS /DDEBUG /ML /Fd
 .c.obj:
        cl $(COMPAT) $(FWHACK) $(CFLAGS) /c $*.c
 
-PUTTYOBJS = window.obj windlg.obj terminal.obj telnet.obj raw.obj xlat.obj
+POBJS1 = window.obj windlg.obj terminal.obj telnet.obj raw.obj
+POBJS2 = xlat.obj ldisc.obj
 OBJS1 = misc.obj noise.obj
 OBJS2 = ssh.obj sshcrc.obj sshdes.obj sshmd5.obj sshrsa.obj sshrand.obj
 OBJS3 = sshsha.obj sshblowf.obj version.obj sizetip.obj
@@ -26,15 +27,16 @@ SCPOBJS3 = sshrsa.obj sshrand.obj sshsha.obj sshblowf.obj version.obj
 
 all: putty.exe pscp.exe
 
-putty.exe: $(PUTTYOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
+putty.exe: $(POBJS1) $(POBJS2) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
        link /debug -out:putty.exe @link.rsp
 
-puttyd.exe: $(PUTTYOBJS) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
+puttyd.exe: $(POBJS1) $(POBJS2) $(OBJS1) $(OBJS2) $(OBJS3) $(RESRC) link.rsp
        link /debug -out:puttyd.exe @link.rsp
 
 link.rsp: makefile
        echo /nologo /subsystem:windows > link.rsp
-       echo $(PUTTYOBJS) >> link.rsp
+       echo $(POBJS1) >> link.rsp
+       echo $(POBJS2) >> link.rsp
        echo $(OBJS1) >> link.rsp
        echo $(OBJS2) >> link.rsp
        echo $(OBJS3) >> link.rsp
@@ -49,6 +51,7 @@ sizetip.obj: sizetip.c putty.h
 telnet.obj: telnet.c putty.h
 raw.obj: raw.c putty.h
 xlat.obj: xlat.c putty.h
+ldisc.obj: ldisc.c putty.h
 misc.obj: misc.c putty.h
 noise.obj: noise.c putty.h ssh.h
 ssh.obj: ssh.c ssh.h putty.h
diff --git a/ldisc.c b/ldisc.c
new file mode 100644 (file)
index 0000000..cb2764e
--- /dev/null
+++ b/ldisc.c
@@ -0,0 +1,137 @@
+#include <windows.h>
+#include <stdio.h>
+
+#include "putty.h"
+
+/*
+ * ldisc.c: PuTTY line disciplines
+ */
+
+static void c_write (char *buf, int len) {
+    while (len--) {
+       int new_head = (inbuf_head + 1) & INBUF_MASK;
+       int c = (unsigned char) *buf;
+       if (new_head != inbuf_reap) {
+           inbuf[inbuf_head] = *buf++;
+           inbuf_head = new_head;
+       }
+    }
+}
+
+static char *term_buf = NULL;
+static int term_buflen = 0, term_bufsiz = 0, term_quotenext = 0;
+
+static int plen(unsigned char c) {
+    if ((c >= 32 && c <= 126) ||
+        (c >= 160))
+        return 1;
+    else if (c < 128)
+        return 2;                      /* ^x for some x */
+    else
+        return 4;                      /* <XY> for hex XY */
+}
+
+static void pwrite(unsigned char c) {
+    if ((c >= 32 && c <= 126) ||
+        (c >= 160)) {
+        char cc = (char)c;
+        c_write(&cc, 1);
+    } else if (c < 128) {
+        char cc[2];
+        cc[1] = (c == 127 ? '?' : c + 0x40);
+        cc[0] = '^';
+        c_write(cc, 2);
+    } else {
+        char cc[5];
+        sprintf(cc, "<%02X>", c);
+        c_write(cc, 4);
+    }
+}
+
+static void bsb(int n) {
+    while (n--)
+       c_write("\010 \010", 3);
+}
+
+static void term_send(char *buf, int len) {
+    while (len--) {
+       char c;
+        c = *buf++;
+       switch (term_quotenext ? ' ' : c) {
+           /*
+            * ^h/^?: delete one char and output one BSB
+            * ^w: delete, and output BSBs, to return to last space/nonspace
+            * boundary
+            * ^u: delete, and output BSBs, to return to BOL
+            * ^r: echo "^R\n" and redraw line
+            * ^v: quote next char
+            * ^d: if at BOL, end of file and close connection, else send line
+            * and reset to BOL
+            * ^m/^j: send line-plus-\r\n and reset to BOL
+            */
+         case 8: case 127:            /* backspace/delete */
+           if (term_buflen > 0) {
+               bsb(plen(term_buf[term_buflen-1]));
+               term_buflen--;
+           }
+           break;
+         case 23:                     /* ^W delete word */
+           while (term_buflen > 0) {
+               bsb(plen(term_buf[term_buflen-1]));
+               term_buflen--;
+               if (term_buflen > 0 &&
+                   isspace(term_buf[term_buflen-1]) &&
+                   !isspace(term_buf[term_buflen]))
+                   break;
+           }
+           break;
+         case 21:                     /* ^U delete line */
+           while (term_buflen > 0) {
+               bsb(plen(term_buf[term_buflen-1]));
+               term_buflen--;
+           }
+            break;
+         case 18:                     /* ^R redraw line */
+           c_write("^R\r\n", 4);
+           {
+               int i;
+               for (i = 0; i < term_buflen; i++)
+                   pwrite(term_buf[i]);
+           }
+           break;
+         case 22:                     /* ^V quote next char */
+           term_quotenext = TRUE;
+           break;
+         case 4:                      /* ^D logout or send */
+           if (term_buflen == 0) {
+               /* FIXME: eof */;
+           } else {
+               back->send(term_buf, term_buflen);
+               term_buflen = 0;
+           }
+           break;
+         case 13: case 10:            /* ^M/^J send with newline */
+           back->send(term_buf, term_buflen);
+           back->send("\r\n", 2);
+           c_write("\r\n", 2);
+           term_buflen = 0;
+           break;
+         default:                     /* get to this label from ^V handler */
+           if (term_buflen >= term_bufsiz) {
+               term_bufsiz = term_buflen + 256;
+               term_buf = saferealloc(term_buf, term_bufsiz);
+           }
+           term_buf[term_buflen++] = c;
+           pwrite(c);
+            term_quotenext = FALSE;
+           break;
+       }
+    }
+}
+
+static void simple_send(char *buf, int len) {
+    back->send(buf, len);
+}
+
+Ldisc ldisc_term = { term_send };
+Ldisc ldisc_simple = { simple_send };
diff --git a/putty.h b/putty.h
index e5744ea..abbb912 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -92,6 +92,12 @@ typedef struct {
 GLOBAL Backend *back;
 
 typedef struct {
+    void (*send) (char *buf, int len);
+} Ldisc;
+
+GLOBAL Ldisc *ldisc;
+
+typedef struct {
     /* Basic options */
     char host[512];
     int port;
@@ -117,6 +123,7 @@ typedef struct {
     int nethack_keypad;
     int alt_f4;                               /* is it special? */
     int alt_space;                    /* is it special? */
+    int ldisc_term;
     /* Terminal options */
     int savelines;
     int dec_om;
@@ -233,6 +240,12 @@ extern Backend telnet_backend;
 extern Backend ssh_backend;
 
 /*
+ * Exports from ldisc.c.
+ */
+
+extern Ldisc ldisc_term, ldisc_simple;
+
+/*
  * Exports from sshrand.c.
  */
 
index f4669df..0218c09 100644 (file)
@@ -577,7 +577,7 @@ void term_out(void) {
            do_toplevel:
            switch (c) {
              case '\005':             /* terminal type query */
-               back->send ("\033[?1;2c", 7);
+               ldisc->send ("\033[?1;2c", 7);
                break;
              case '\007':
                beep();
@@ -766,7 +766,7 @@ void term_out(void) {
                must_update = TRUE;
                break;
              case 'Z':                /* terminal type query */
-               back->send ("\033[?6c", 5);
+               ldisc->send ("\033[?6c", 5);
                break;
              case 'c':                /* restore power-on settings */
                power_on();
@@ -902,13 +902,13 @@ void term_out(void) {
                must_update = TRUE;
                break;
              case 'c':                /* terminal type query */
-               back->send ("\033[?6c", 5);
+               ldisc->send ("\033[?6c", 5);
                break;
              case 'n':                /* cursor position query */
                if (esc_args[0] == 6) {
                    char buf[32];
                    sprintf (buf, "\033[%d;%dR", curs_y + 1, curs_x + 1);
-                   back->send (buf, strlen(buf));
+                   ldisc->send (buf, strlen(buf));
                }
                break;
              case 'h':                /* toggle a mode to high */
@@ -1031,7 +1031,7 @@ void term_out(void) {
                    if (i == 0 || i == 1) {
                        strcpy (buf, "\033[2;1;1;112;112;1;0x");
                        buf[2] += i;
-                       back->send (buf, 20);
+                       ldisc->send (buf, 20);
                    }
                }
                break;
@@ -1443,13 +1443,13 @@ void term_mouse (Mouse_Button b, Mouse_Action a, int x, int y) {
                    for(i=0;i<p-q;i++)
                    {
                        c=xlat_kbd2tty(q[i]);
-                       back->send(&c,1);
+                       ldisc->send(&c,1);
                    }
                }
 
                if (p <= data+len-sizeof(sel_nl) &&
                    !memcmp(p, sel_nl, sizeof(sel_nl))) {
-                   back->send ("\r", 1);
+                   ldisc->send ("\r", 1);
                    p += sizeof(sel_nl);
                }
                q = p;
index aec42f6..4d6446e 100644 (file)
--- a/win_res.h
+++ b/win_res.h
@@ -63,6 +63,7 @@
 #define IDC1_CURAPPLIC  1016
 #define IDC1_ALTF4      1017
 #define IDC1_ALTSPACE   1018
+#define IDC1_LDISCTERM  1019
 
 #define IDC2_WRAPMODE   1001
 #define IDC2_DECOM      1002
index 37b5eca..c1f8094 100644 (file)
@@ -105,6 +105,8 @@ BEGIN
         IDC1_ALTF4, 3, 113, 162, 10
     AUTOCHECKBOX "ALT-Space is special (S&ystem menu)",
         IDC1_ALTSPACE, 3, 123, 162, 10
+    AUTOCHECKBOX "&Use local terminal line discipline",
+        IDC1_LDISCTERM, 3, 133, 162, 10
 END
 
 IDD_PANEL2 DIALOG DISCARDABLE 6, 30, 168, 163
index 69f91fb..0a8f800 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -157,6 +157,7 @@ static void save_settings (char *section, int do_host) {
     wppi (sesskey, "NetHackKeypad", cfg.nethack_keypad);
     wppi (sesskey, "AltF4", cfg.alt_f4);
     wppi (sesskey, "AltSpace", cfg.alt_space);
+    wppi (sesskey, "LdiscTerm", cfg.ldisc_term);
     wppi (sesskey, "ScrollbackLines", cfg.savelines);
     wppi (sesskey, "DECOriginMode", cfg.dec_om);
     wppi (sesskey, "AutoWrapMode", cfg.wrap_mode);
@@ -290,6 +291,7 @@ static void load_settings (char *section, int do_host) {
     gppi (sesskey, "NetHackKeypad", 0, &cfg.nethack_keypad);
     gppi (sesskey, "AltF4", 1, &cfg.alt_f4);
     gppi (sesskey, "AltSpace", 0, &cfg.alt_space);
+    gppi (sesskey, "LdiscTerm", 0, &cfg.ldisc_term);
     gppi (sesskey, "ScrollbackLines", 200, &cfg.savelines);
     gppi (sesskey, "DECOriginMode", 0, &cfg.dec_om);
     gppi (sesskey, "AutoWrapMode", 1, &cfg.wrap_mode);
@@ -636,6 +638,7 @@ static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
                          cfg.app_keypad ? IDC1_KPAPPLIC : IDC1_KPNORMAL);
        CheckDlgButton (hwnd, IDC1_ALTF4, cfg.alt_f4);
        CheckDlgButton (hwnd, IDC1_ALTSPACE, cfg.alt_space);
+       CheckDlgButton (hwnd, IDC1_LDISCTERM, cfg.ldisc_term);
        break;
       case WM_COMMAND:
        if (HIWORD(wParam) == BN_CLICKED ||
@@ -676,6 +679,11 @@ static int CALLBACK KeyboardProc (HWND hwnd, UINT msg,
                    HIWORD(wParam) == BN_DOUBLECLICKED)
                    cfg.alt_space = IsDlgButtonChecked (hwnd, IDC1_ALTSPACE);
                break;
+             case IDC1_LDISCTERM:
+               if (HIWORD(wParam) == BN_CLICKED ||
+                   HIWORD(wParam) == BN_DOUBLECLICKED)
+                   cfg.ldisc_term = IsDlgButtonChecked (hwnd, IDC1_LDISCTERM);
+               break;
            }
     }
     return GeneralPanelProc (hwnd, msg, wParam, lParam);
index dd1365c..a636ac5 100644 (file)
--- a/window.c
+++ b/window.c
@@ -181,7 +181,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
     }
 
     back = (cfg.protocol == PROT_SSH ? &ssh_backend : 
-                       cfg.protocol == PROT_TELNET ? &telnet_backend : &raw_backend );
+           cfg.protocol == PROT_TELNET ? &telnet_backend :
+           &raw_backend);
+
+    ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
 
     if (!prev) {
        wndclass.style         = 0;
@@ -1016,7 +1019,7 @@ static int WINAPI WndProc (HWND hwnd, UINT message,
            len = TranslateKey (wParam, lParam, buf);
            if (len == -1)
                return DefWindowProc (hwnd, message, wParam, lParam);
-           back->send (buf, len);
+           ldisc->send (buf, len);
        }
        return 0;
       case WM_KEYUP:
@@ -1056,7 +1059,7 @@ static int WINAPI WndProc (HWND hwnd, UINT message,
         */
        {
            char c = xlat_kbd2tty((unsigned char)wParam);
-           back->send (&c, 1);
+           ldisc->send (&c, 1);
        }
        return 0;
     }