]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - ldisc.c
Run entire source base through GNU indent to tidy up the varying
[PuTTY.git] / ldisc.c
1 /*
2  * ldisc.c: PuTTY line discipline. Sits between the input coming
3  * from keypresses in the window, and the output channel leading to
4  * the back end. Implements echo and/or local line editing,
5  * depending on what's currently configured.
6  */
7
8 #include <windows.h>
9 #include <stdio.h>
10 #include <ctype.h>
11
12 #include "putty.h"
13
14 #define ECHOING (cfg.localecho == LD_YES || \
15                  (cfg.localecho == LD_BACKEND && \
16                       (back->ldisc(LD_ECHO) || term_ldisc(LD_ECHO))))
17 #define EDITING (cfg.localedit == LD_YES || \
18                  (cfg.localedit == LD_BACKEND && \
19                       (back->ldisc(LD_EDIT) || term_ldisc(LD_EDIT))))
20
21 static void c_write(char *buf, int len)
22 {
23     from_backend(0, buf, len);
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 {
31     if ((c >= 32 && c <= 126) || (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 {
41     if ((c >= 32 && c <= 126) || (c >= 160)) {
42         c_write(&c, 1);
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 {
57     while (n--)
58         c_write("\010 \010", 3);
59 }
60
61 #define CTRL(x) (x^'@')
62
63 void ldisc_send(char *buf, int len)
64 {
65     /*
66      * Called with len=0 when the options change. We must inform
67      * the front end in case it needs to know.
68      */
69     if (len == 0) {
70         void ldisc_update(int echo, int edit);
71         ldisc_update(ECHOING, EDITING);
72     }
73     /*
74      * Either perform local editing, or just send characters.
75      */
76     if (EDITING) {
77         while (len--) {
78             char c;
79             c = *buf++;
80             switch (term_quotenext ? ' ' : c) {
81                 /*
82                  * ^h/^?: delete one char and output one BSB
83                  * ^w: delete, and output BSBs, to return to last
84                  * space/nonspace boundary
85                  * ^u: delete, and output BSBs, to return to BOL
86                  * ^c: Do a ^u then send a telnet IP
87                  * ^z: Do a ^u then send a telnet SUSP
88                  * ^\: Do a ^u then send a telnet ABORT
89                  * ^r: echo "^R\n" and redraw line
90                  * ^v: quote next char
91                  * ^d: if at BOL, end of file and close connection,
92                  * else send line and reset to BOL
93                  * ^m: send line-plus-\r\n and reset to BOL
94                  */
95               case CTRL('H'):
96               case CTRL('?'):          /* backspace/delete */
97                 if (term_buflen > 0) {
98                     if (ECHOING)
99                         bsb(plen(term_buf[term_buflen - 1]));
100                     term_buflen--;
101                 }
102                 break;
103               case CTRL('W'):          /* delete word */
104                 while (term_buflen > 0) {
105                     if (ECHOING)
106                         bsb(plen(term_buf[term_buflen - 1]));
107                     term_buflen--;
108                     if (term_buflen > 0 &&
109                         isspace(term_buf[term_buflen - 1]) &&
110                         !isspace(term_buf[term_buflen]))
111                         break;
112                 }
113                 break;
114               case CTRL('U'):          /* delete line */
115               case CTRL('C'):          /* Send IP */
116               case CTRL('\\'):         /* Quit */
117               case CTRL('Z'):          /* Suspend */
118                 while (term_buflen > 0) {
119                     if (ECHOING)
120                         bsb(plen(term_buf[term_buflen - 1]));
121                     term_buflen--;
122                 }
123                 back->special(TS_EL);
124                 if (c == CTRL('C'))
125                     back->special(TS_IP);
126                 if (c == CTRL('Z'))
127                     back->special(TS_SUSP);
128                 if (c == CTRL('\\'))
129                     back->special(TS_ABORT);
130                 break;
131               case CTRL('R'):          /* redraw line */
132                 if (ECHOING) {
133                     int i;
134                     c_write("^R\r\n", 4);
135                     for (i = 0; i < term_buflen; i++)
136                         pwrite(term_buf[i]);
137                 }
138                 break;
139               case CTRL('V'):          /* quote next char */
140                 term_quotenext = TRUE;
141                 break;
142               case CTRL('D'):          /* logout or send */
143                 if (term_buflen == 0) {
144                     back->special(TS_EOF);
145                 } else {
146                     back->send(term_buf, term_buflen);
147                     term_buflen = 0;
148                 }
149                 break;
150               case CTRL('M'):          /* send with newline */
151                 if (term_buflen > 0)
152                     back->send(term_buf, term_buflen);
153                 if (cfg.protocol == PROT_RAW)
154                     back->send("\r\n", 2);
155                 else
156                     back->send("\r", 1);
157                 if (ECHOING)
158                     c_write("\r\n", 2);
159                 term_buflen = 0;
160                 break;
161               default:                 /* get to this label from ^V handler */
162                 if (term_buflen >= term_bufsiz) {
163                     term_bufsiz = term_buflen + 256;
164                     term_buf = saferealloc(term_buf, term_bufsiz);
165                 }
166                 term_buf[term_buflen++] = c;
167                 if (ECHOING)
168                     pwrite(c);
169                 term_quotenext = FALSE;
170                 break;
171             }
172         }
173     } else {
174         if (term_buflen != 0) {
175             back->send(term_buf, term_buflen);
176             while (term_buflen > 0) {
177                 bsb(plen(term_buf[term_buflen - 1]));
178                 term_buflen--;
179             }
180         }
181         if (len > 0) {
182             if (ECHOING)
183                 c_write(buf, len);
184             back->send(buf, len);
185         }
186     }
187 }