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