]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - ldisc.c
Introduce a sane interface function, from_backend(), for backends to
[PuTTY.git] / ldisc.c
1 #include <windows.h>
2 #ifndef AUTO_WINSOCK
3 #ifdef WINSOCK_TWO
4 #include <winsock2.h>
5 #else
6 #include <winsock.h>
7 #endif
8 #endif
9 #include <stdio.h>
10 #include <ctype.h>
11
12 #include "putty.h"
13
14 /*
15  * ldisc.c: PuTTY line disciplines
16  */
17
18 static void c_write (char *buf, int len) {
19     from_backend(0, buf, len);
20 }
21
22 static void c_write1 (char c) {
23     c_write(&c, 1);
24 }
25
26 static char *term_buf = NULL;
27 static int term_buflen = 0, term_bufsiz = 0, term_quotenext = 0;
28
29 static int plen(unsigned char c) {
30     if ((c >= 32 && c <= 126) ||
31         (c >= 160))
32         return 1;
33     else if (c < 128)
34         return 2;                      /* ^x for some x */
35     else
36         return 4;                      /* <XY> for hex XY */
37 }
38
39 static void pwrite(unsigned char c) {
40     if ((c >= 32 && c <= 126) ||
41         (c >= 160)) {
42         c_write1(c);
43     } else if (c < 128) {
44         char cc[2];
45         cc[1] = (c == 127 ? '?' : c + 0x40);
46         cc[0] = '^';
47         c_write(cc, 2);
48     } else {
49         char cc[5];
50         sprintf(cc, "<%02X>", c);
51         c_write(cc, 4);
52     }
53 }
54
55 static void bsb(int n) {
56     while (n--)
57         c_write("\010 \010", 3);
58 }
59
60 #define CTRL(x) (x^'@')
61
62 static void term_send(char *buf, int len) {
63     while (len--) {
64         char c;
65         c = *buf++;
66         switch (term_quotenext ? ' ' : c) {
67             /*
68              * ^h/^?: delete one char and output one BSB
69              * ^w: delete, and output BSBs, to return to last space/nonspace
70              * boundary
71              * ^u: delete, and output BSBs, to return to BOL
72              * ^c: Do a ^u then send a telnet IP
73              * ^z: Do a ^u then send a telnet SUSP
74              * ^\: Do a ^u then send a telnet ABORT
75              * ^r: echo "^R\n" and redraw line
76              * ^v: quote next char
77              * ^d: if at BOL, end of file and close connection, else send line
78              * and reset to BOL
79              * ^m: send line-plus-\r\n and reset to BOL
80              */
81           case CTRL('H'): case CTRL('?'):      /* backspace/delete */
82             if (term_buflen > 0) {
83                 bsb(plen(term_buf[term_buflen-1]));
84                 term_buflen--;
85             }
86             break;
87           case CTRL('W'):                      /* delete word */
88             while (term_buflen > 0) {
89                 bsb(plen(term_buf[term_buflen-1]));
90                 term_buflen--;
91                 if (term_buflen > 0 &&
92                     isspace(term_buf[term_buflen-1]) &&
93                     !isspace(term_buf[term_buflen]))
94                     break;
95             }
96             break;
97           case CTRL('U'):              /* delete line */
98           case CTRL('C'):              /* Send IP */
99           case CTRL('\\'):             /* Quit */
100           case CTRL('Z'):              /* Suspend */
101             while (term_buflen > 0) {
102                 bsb(plen(term_buf[term_buflen-1]));
103                 term_buflen--;
104             }
105             back->special (TS_EL);
106             if( c == CTRL('C') )  back->special (TS_IP);
107             if( c == CTRL('Z') )  back->special (TS_SUSP);
108             if( c == CTRL('\\') ) back->special (TS_ABORT);
109             break;
110           case CTRL('R'):              /* redraw line */
111             c_write("^R\r\n", 4);
112             {
113                 int i;
114                 for (i = 0; i < term_buflen; i++)
115                     pwrite(term_buf[i]);
116             }
117             break;
118           case CTRL('V'):              /* quote next char */
119             term_quotenext = TRUE;
120             break;
121           case CTRL('D'):              /* logout or send */
122             if (term_buflen == 0) {
123                 back->special (TS_EOF);
124             } else {
125                 back->send(term_buf, term_buflen);
126                 term_buflen = 0;
127             }
128             break;
129           case CTRL('M'):              /* send with newline */
130             if (term_buflen > 0)
131                 back->send(term_buf, term_buflen);
132             if (cfg.protocol == PROT_RAW)
133                 back->send("\r\n", 2);
134             else
135                 back->send("\r", 1);
136             c_write("\r\n", 2);
137             term_buflen = 0;
138             break;
139           default:                     /* get to this label from ^V handler */
140             if (term_buflen >= term_bufsiz) {
141                 term_bufsiz = term_buflen + 256;
142                 term_buf = saferealloc(term_buf, term_bufsiz);
143             }
144             term_buf[term_buflen++] = c;
145             pwrite(c);
146             term_quotenext = FALSE;
147             break;
148         }
149     }
150 }
151
152 static void simple_send(char *buf, int len) {
153     if( term_buflen != 0 )
154     {
155         back->send(term_buf, term_buflen);
156         while (term_buflen > 0) {
157             bsb(plen(term_buf[term_buflen-1]));
158             term_buflen--;
159         }
160     }
161     if (len > 0)
162         back->send(buf, len);
163 }
164
165 Ldisc ldisc_term = { term_send };
166 Ldisc ldisc_simple = { simple_send };