1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/ldiscucs.c
Simon Tatham 053d2ba6d1 Patch from Yoshida Masato to fill in the missing pieces of Windows
UTF-16 support. High Unicode characters in the terminal are now
converted back into surrogates during copy and draw operations, and
the Windows drawing code takes account of that when splitting up the
UTF-16 string for display. Meanwhile, accidental uses of wchar_t have
been replaced with 32-bit integers in parts of the cross-platform code
which were expecting not to have to deal with UTF-16.

[originally from svn r9409]
2012-02-17 19:28:55 +00:00

100 lines
2.3 KiB
C

/*
* ldisc.c: PuTTY line discipline. Sits between the input coming
* from keypresses in the window, and the output channel leading to
* the back end. Implements echo and/or local line editing,
* depending on what's currently configured.
*/
#include <stdio.h>
#include <ctype.h>
#include "putty.h"
#include "terminal.h"
#include "ldisc.h"
void lpage_send(void *handle,
int codepage, char *buf, int len, int interactive)
{
Ldisc ldisc = (Ldisc)handle;
wchar_t *widebuffer = 0;
int widesize = 0;
int wclen;
if (codepage < 0) {
ldisc_send(ldisc, buf, len, interactive);
return;
}
widesize = len * 2;
widebuffer = snewn(widesize, wchar_t);
wclen = mb_to_wc(codepage, 0, buf, len, widebuffer, widesize);
luni_send(ldisc, widebuffer, wclen, interactive);
sfree(widebuffer);
}
void luni_send(void *handle, wchar_t * widebuf, int len, int interactive)
{
Ldisc ldisc = (Ldisc)handle;
int ratio = (in_utf(ldisc->term))?3:1;
char *linebuffer;
int linesize;
int i;
char *p;
linesize = len * ratio * 2;
linebuffer = snewn(linesize, char);
if (in_utf(ldisc->term)) {
/* UTF is a simple algorithm */
for (p = linebuffer, i = 0; i < len; i++) {
unsigned long ch = widebuf[i];
if (IS_SURROGATE(ch)) {
#ifdef PLATFORM_IS_UTF16
if (i+1 < len) {
unsigned long ch2 = widebuf[i+1];
if (IS_SURROGATE_PAIR(ch, ch2)) {
ch = FROM_SURROGATES(ch, ch2);
i++;
}
} else
#endif
{
/* Unrecognised UTF-16 sequence */
ch = '.';
}
}
if (ch < 0x80) {
*p++ = (char) (ch);
} else if (ch < 0x800) {
*p++ = (char) (0xC0 | (ch >> 6));
*p++ = (char) (0x80 | (ch & 0x3F));
} else if (ch < 0x10000) {
*p++ = (char) (0xE0 | (ch >> 12));
*p++ = (char) (0x80 | ((ch >> 6) & 0x3F));
*p++ = (char) (0x80 | (ch & 0x3F));
} else {
*p++ = (char) (0xF0 | (ch >> 18));
*p++ = (char) (0x80 | ((ch >> 12) & 0x3F));
*p++ = (char) (0x80 | ((ch >> 6) & 0x3F));
*p++ = (char) (0x80 | (ch & 0x3F));
}
}
} else {
int rv;
rv = wc_to_mb(ldisc->term->ucsdata->line_codepage, 0, widebuf, len,
linebuffer, linesize, NULL, NULL, ldisc->term->ucsdata);
if (rv >= 0)
p = linebuffer + rv;
else
p = linebuffer;
}
if (p > linebuffer)
ldisc_send(ldisc, linebuffer, p - linebuffer, interactive);
sfree(linebuffer);
}