X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/2dc6356a02ebe2e5c0428cefc18e64882d85b4a6..7b56a33fca0f6c9130188db0d2eb475de9380b02:/unix/uxucs.c diff --git a/unix/uxucs.c b/unix/uxucs.c index 2bf65a8a..9d8242f8 100644 --- a/unix/uxucs.c +++ b/unix/uxucs.c @@ -8,6 +8,7 @@ #include #include "putty.h" +#include "charset.h" #include "terminal.h" #include "misc.h" @@ -20,14 +21,14 @@ int is_dbcs_leadbyte(int codepage, char byte) return 0; /* we don't do DBCS */ } -int mb_to_wc(int codepage, int flags, char *mbstr, int mblen, +int mb_to_wc(int codepage, int flags, const char *mbstr, int mblen, wchar_t *wcstr, int wclen) { if (codepage == DEFAULT_CODEPAGE) { int n = 0; - mbstate_t state = { 0 }; + mbstate_t state; - setlocale(LC_CTYPE, ""); + memset(&state, 0, sizeof state); while (mblen > 0) { size_t i = mbrtowc(wcstr+n, mbstr, (size_t)mblen, &state); @@ -38,7 +39,16 @@ int mb_to_wc(int codepage, int flags, char *mbstr, int mblen, mblen -= i; } - setlocale(LC_CTYPE, "C"); + return n; + } else if (codepage == CS_NONE) { + int n = 0; + + while (mblen > 0) { + wcstr[n] = 0xD800 | (mbstr[0] & 0xFF); + n++; + mbstr++; + mblen--; + } return n; } else @@ -46,8 +56,9 @@ int mb_to_wc(int codepage, int flags, char *mbstr, int mblen, NULL, NULL, 0); } -int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen, - char *mbstr, int mblen, char *defchr, int *defused) +int wc_to_mb(int codepage, int flags, const wchar_t *wcstr, int wclen, + char *mbstr, int mblen, char *defchr, int *defused, + struct unicode_data *ucsdata) { /* FIXME: we should remove the defused param completely... */ if (defused) @@ -55,10 +66,10 @@ int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen, if (codepage == DEFAULT_CODEPAGE) { char output[MB_LEN_MAX]; - mbstate_t state = { 0 }; + mbstate_t state; int n = 0; - setlocale(LC_CTYPE, ""); + memset(&state, 0, sizeof state); while (wclen > 0) { int i = wcrtomb(output, wcstr[0], &state); @@ -70,17 +81,31 @@ int wc_to_mb(int codepage, int flags, wchar_t *wcstr, int wclen, wclen--; } - setlocale(LC_CTYPE, "C"); - return n; - } else + } else if (codepage == CS_NONE) { + int n = 0; + while (wclen > 0 && n < mblen) { + if (*wcstr >= 0xD800 && *wcstr < 0xD900) + mbstr[n++] = (*wcstr & 0xFF); + else if (defchr) + mbstr[n++] = *defchr; + wcstr++; + wclen--; + } + return n; + } else { return charset_from_unicode(&wcstr, &wclen, mbstr, mblen, codepage, - NULL, NULL, 0); + NULL, defchr?defchr:NULL, defchr?1:0); + } } -void init_ucs(void) +/* + * Return value is TRUE if pterm is to run in direct-to-font mode. + */ +int init_ucs(struct unicode_data *ucsdata, char *linecharset, + int utf8_override, int font_charset, int vtmode) { - int i; + int i, ret = 0; /* * In the platform-independent parts of the code, font_codepage @@ -88,39 +113,64 @@ void init_ucs(void) * support at all. So we set this to something which will never * be used. */ - font_codepage = -1; + ucsdata->font_codepage = -1; /* - * line_codepage should be decoded from the specification in - * cfg. + * If utf8_override is set and the POSIX locale settings + * dictate a UTF-8 character set, then just go straight for + * UTF-8. */ - line_codepage = charset_from_mimeenc(cfg.line_codepage); - if (line_codepage == CS_NONE) - line_codepage = charset_from_xenc(cfg.line_codepage); - /* If it's still CS_NONE, we should assume direct-to-font. */ - - /* FIXME: this is a hack. Currently fonts with incomprehensible - * encodings are dealt with by pretending they're 8859-1. It's - * ugly, but it's good enough to stop things crashing. Should do - * something better here. */ - if (line_codepage == CS_NONE) - line_codepage = CS_ISO8859_1; + ucsdata->line_codepage = CS_NONE; + if (utf8_override) { + const char *s; + if (((s = getenv("LC_ALL")) && *s) || + ((s = getenv("LC_CTYPE")) && *s) || + ((s = getenv("LANG")) && *s)) { + if (strstr(s, "UTF-8")) + ucsdata->line_codepage = CS_UTF8; + } + } + + /* + * Failing that, line_codepage should be decoded from the + * specification in conf. + */ + if (ucsdata->line_codepage == CS_NONE) + ucsdata->line_codepage = decode_codepage(linecharset); + + /* + * If line_codepage is _still_ CS_NONE, we assume we're using + * the font's own encoding. This has been passed in to us, so + * we use that. If it's still CS_NONE after _that_ - i.e. the + * font we were given had an incomprehensible charset - then we + * fall back to using the D800 page. + */ + if (ucsdata->line_codepage == CS_NONE) + ucsdata->line_codepage = font_charset; + + if (ucsdata->line_codepage == CS_NONE) + ret = 1; /* * Set up unitab_line, by translating each individual character * in the line codepage into Unicode. */ for (i = 0; i < 256; i++) { - char c[1], *p; + char c[1]; + const char *p; wchar_t wc[1]; int len; c[0] = i; p = c; len = 1; - if (1 == charset_to_unicode(&p,&len,wc,1,line_codepage,NULL,L"",0)) - unitab_line[i] = wc[0]; + if (ucsdata->line_codepage == CS_NONE) + ucsdata->unitab_line[i] = 0xD800 | i; + else if (1 == charset_to_unicode(&p, &len, wc, 1, + ucsdata->line_codepage, + NULL, L"", 0)) + ucsdata->unitab_line[i] = wc[0]; else - unitab_line[i] = 0xFFFD; + ucsdata->unitab_line[i] = 0xFFFD; } /* @@ -140,10 +190,20 @@ void init_ucs(void) 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020 }; + static const wchar_t unitab_xterm_poorman[32] = + L"*#****o~**+++++-----++++|****L. "; + + const wchar_t *ptr; + + if (vtmode == VT_POORMAN) + ptr = unitab_xterm_poorman; + else + ptr = unitab_xterm_std; + if (i >= 0x5F && i < 0x7F) - unitab_xterm[i] = unitab_xterm_std[i & 0x1F]; + ucsdata->unitab_xterm[i] = ptr[i & 0x1F]; else - unitab_xterm[i] = unitab_line[i]; + ucsdata->unitab_xterm[i] = ucsdata->unitab_line[i]; } /* @@ -151,23 +211,59 @@ void init_ucs(void) * simply CP437. */ for (i = 0; i < 256; i++) { - char c[1], *p; + char c[1]; + const char *p; wchar_t wc[1]; int len; c[0] = i; p = c; len = 1; - if (1 == charset_to_unicode(&p,&len,wc,1,CS_CP437,NULL,L"",0)) - unitab_scoacs[i] = wc[0]; + if (1 == charset_to_unicode(&p, &len, wc, 1, CS_CP437, NULL, L"", 0)) + ucsdata->unitab_scoacs[i] = wc[0]; else - unitab_scoacs[i] = 0xFFFD; + ucsdata->unitab_scoacs[i] = 0xFFFD; } - /* Find the line control characters. */ - for (i = 0; i < 256; i++) - if (unitab_line[i] < ' ' - || (unitab_line[i] >= 0x7F && unitab_line[i] < 0xA0)) - unitab_ctrl[i] = i; + /* + * Find the control characters in the line codepage. For + * direct-to-font mode using the D800 hack, we assume 00-1F and + * 7F are controls, but allow 80-9F through. (It's as good a + * guess as anything; and my bet is that half the weird fonts + * used in this way will be IBM or MS code pages anyway.) + */ + for (i = 0; i < 256; i++) { + int lineval = ucsdata->unitab_line[i]; + if (lineval < ' ' || (lineval >= 0x7F && lineval < 0xA0) || + (lineval >= 0xD800 && lineval < 0xD820) || (lineval == 0xD87F)) + ucsdata->unitab_ctrl[i] = i; else - unitab_ctrl[i] = 0xFF; + ucsdata->unitab_ctrl[i] = 0xFF; + } + + return ret; +} + +const char *cp_name(int codepage) +{ + if (codepage == CS_NONE) + return "Use font encoding"; + return charset_to_localenc(codepage); +} + +const char *cp_enumerate(int index) +{ + int charset; + if (index == 0) + return "Use font encoding"; + charset = charset_localenc_nth(index-1); + if (charset == CS_NONE) + return NULL; + return charset_to_localenc(charset); +} + +int decode_codepage(char *cp_name) +{ + if (!*cp_name) + return CS_NONE; /* use font encoding */ + return charset_from_localenc(cp_name); }