5bc238bb |
1 | #include <windows.h> |
2 | #include <stdio.h> |
1d470ad2 |
3 | #include <ctype.h> |
5bc238bb |
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 | int new_head = (inbuf_head + 1) & INBUF_MASK; |
14 | int c = (unsigned char) *buf; |
15 | if (new_head != inbuf_reap) { |
16 | inbuf[inbuf_head] = *buf++; |
17 | inbuf_head = new_head; |
18 | } |
19 | } |
20 | } |
21 | |
22 | static char *term_buf = NULL; |
23 | static int term_buflen = 0, term_bufsiz = 0, term_quotenext = 0; |
24 | |
25 | static int plen(unsigned char c) { |
26 | if ((c >= 32 && c <= 126) || |
27 | (c >= 160)) |
28 | return 1; |
29 | else if (c < 128) |
30 | return 2; /* ^x for some x */ |
31 | else |
32 | return 4; /* <XY> for hex XY */ |
33 | } |
34 | |
35 | static void pwrite(unsigned char c) { |
36 | if ((c >= 32 && c <= 126) || |
37 | (c >= 160)) { |
38 | char cc = (char)c; |
39 | c_write(&cc, 1); |
40 | } else if (c < 128) { |
41 | char cc[2]; |
42 | cc[1] = (c == 127 ? '?' : c + 0x40); |
43 | cc[0] = '^'; |
44 | c_write(cc, 2); |
45 | } else { |
46 | char cc[5]; |
47 | sprintf(cc, "<%02X>", c); |
48 | c_write(cc, 4); |
49 | } |
50 | } |
51 | |
52 | static void bsb(int n) { |
53 | while (n--) |
54 | c_write("\010 \010", 3); |
55 | } |
56 | |
57 | static void term_send(char *buf, int len) { |
58 | while (len--) { |
59 | char c; |
60 | c = *buf++; |
61 | switch (term_quotenext ? ' ' : c) { |
62 | /* |
63 | * ^h/^?: delete one char and output one BSB |
64 | * ^w: delete, and output BSBs, to return to last space/nonspace |
65 | * boundary |
66 | * ^u: delete, and output BSBs, to return to BOL |
67 | * ^r: echo "^R\n" and redraw line |
68 | * ^v: quote next char |
69 | * ^d: if at BOL, end of file and close connection, else send line |
70 | * and reset to BOL |
71 | * ^m/^j: send line-plus-\r\n and reset to BOL |
72 | */ |
73 | case 8: case 127: /* backspace/delete */ |
74 | if (term_buflen > 0) { |
75 | bsb(plen(term_buf[term_buflen-1])); |
76 | term_buflen--; |
77 | } |
78 | break; |
79 | case 23: /* ^W delete word */ |
80 | while (term_buflen > 0) { |
81 | bsb(plen(term_buf[term_buflen-1])); |
82 | term_buflen--; |
83 | if (term_buflen > 0 && |
84 | isspace(term_buf[term_buflen-1]) && |
85 | !isspace(term_buf[term_buflen])) |
86 | break; |
87 | } |
88 | break; |
89 | case 21: /* ^U delete line */ |
90 | while (term_buflen > 0) { |
91 | bsb(plen(term_buf[term_buflen-1])); |
92 | term_buflen--; |
93 | } |
94 | break; |
95 | case 18: /* ^R redraw line */ |
96 | c_write("^R\r\n", 4); |
97 | { |
98 | int i; |
99 | for (i = 0; i < term_buflen; i++) |
100 | pwrite(term_buf[i]); |
101 | } |
102 | break; |
103 | case 22: /* ^V quote next char */ |
104 | term_quotenext = TRUE; |
105 | break; |
106 | case 4: /* ^D logout or send */ |
107 | if (term_buflen == 0) { |
108 | /* FIXME: eof */; |
109 | } else { |
110 | back->send(term_buf, term_buflen); |
111 | term_buflen = 0; |
112 | } |
113 | break; |
114 | case 13: case 10: /* ^M/^J send with newline */ |
115 | back->send(term_buf, term_buflen); |
116 | back->send("\r\n", 2); |
117 | c_write("\r\n", 2); |
118 | term_buflen = 0; |
119 | break; |
120 | default: /* get to this label from ^V handler */ |
121 | if (term_buflen >= term_bufsiz) { |
122 | term_bufsiz = term_buflen + 256; |
123 | term_buf = saferealloc(term_buf, term_bufsiz); |
124 | } |
125 | term_buf[term_buflen++] = c; |
126 | pwrite(c); |
127 | term_quotenext = FALSE; |
128 | break; |
129 | } |
130 | } |
131 | } |
132 | |
133 | static void simple_send(char *buf, int len) { |
134 | back->send(buf, len); |
135 | } |
136 | |
137 | Ldisc ldisc_term = { term_send }; |
138 | Ldisc ldisc_simple = { simple_send }; |