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