]>
Commit | Line | Data |
---|---|---|
1c1af145 | 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 <stdio.h> | |
9 | #include <ctype.h> | |
10 | ||
11 | #include "putty.h" | |
12 | #include "terminal.h" | |
13 | #include "ldisc.h" | |
14 | ||
15 | void lpage_send(void *handle, | |
16 | int codepage, char *buf, int len, int interactive) | |
17 | { | |
18 | Ldisc ldisc = (Ldisc)handle; | |
19 | wchar_t *widebuffer = 0; | |
20 | int widesize = 0; | |
21 | int wclen; | |
22 | ||
23 | if (codepage < 0) { | |
24 | ldisc_send(ldisc, buf, len, interactive); | |
25 | return; | |
26 | } | |
27 | ||
28 | widesize = len * 2; | |
29 | widebuffer = snewn(widesize, wchar_t); | |
30 | ||
31 | wclen = mb_to_wc(codepage, 0, buf, len, widebuffer, widesize); | |
32 | luni_send(ldisc, widebuffer, wclen, interactive); | |
33 | ||
34 | sfree(widebuffer); | |
35 | } | |
36 | ||
37 | void luni_send(void *handle, wchar_t * widebuf, int len, int interactive) | |
38 | { | |
39 | Ldisc ldisc = (Ldisc)handle; | |
40 | int ratio = (in_utf(ldisc->term))?3:1; | |
41 | char *linebuffer; | |
42 | int linesize; | |
43 | int i; | |
44 | char *p; | |
45 | ||
46 | linesize = len * ratio * 2; | |
47 | linebuffer = snewn(linesize, char); | |
48 | ||
49 | if (in_utf(ldisc->term)) { | |
50 | /* UTF is a simple algorithm */ | |
51 | for (p = linebuffer, i = 0; i < len; i++) { | |
52 | unsigned long ch = widebuf[i]; | |
53 | ||
54 | if ((ch & 0xF800) == 0xD800) { | |
55 | #ifdef PLATFORM_IS_UTF16 | |
56 | if (i+1 < len) { | |
57 | unsigned long ch2 = widebuf[i+1]; | |
58 | if ((ch & 0xFC00) == 0xD800 && | |
59 | (ch2 & 0xFC00) == 0xDC00) { | |
60 | ch = 0x10000 + ((ch & 0x3FF) << 10) + (ch2 & 0x3FF); | |
61 | i++; | |
62 | } | |
63 | } else | |
64 | #endif | |
65 | { | |
66 | /* Unrecognised UTF-16 sequence */ | |
67 | ch = '.'; | |
68 | } | |
69 | } | |
70 | ||
71 | if (ch < 0x80) { | |
72 | *p++ = (char) (ch); | |
73 | } else if (ch < 0x800) { | |
74 | *p++ = (char) (0xC0 | (ch >> 6)); | |
75 | *p++ = (char) (0x80 | (ch & 0x3F)); | |
76 | } else if (ch < 0x10000) { | |
77 | *p++ = (char) (0xE0 | (ch >> 12)); | |
78 | *p++ = (char) (0x80 | ((ch >> 6) & 0x3F)); | |
79 | *p++ = (char) (0x80 | (ch & 0x3F)); | |
80 | } else { | |
81 | *p++ = (char) (0xF0 | (ch >> 18)); | |
82 | *p++ = (char) (0x80 | ((ch >> 12) & 0x3F)); | |
83 | *p++ = (char) (0x80 | ((ch >> 6) & 0x3F)); | |
84 | *p++ = (char) (0x80 | (ch & 0x3F)); | |
85 | } | |
86 | } | |
87 | } else { | |
88 | int rv; | |
89 | rv = wc_to_mb(ldisc->term->ucsdata->line_codepage, 0, widebuf, len, | |
90 | linebuffer, linesize, NULL, NULL, ldisc->term->ucsdata); | |
91 | if (rv >= 0) | |
92 | p = linebuffer + rv; | |
93 | else | |
94 | p = linebuffer; | |
95 | } | |
96 | if (p > linebuffer) | |
97 | ldisc_send(ldisc, linebuffer, p - linebuffer, interactive); | |
98 | ||
99 | sfree(linebuffer); | |
100 | } |