From 4eeb7d098fc3c6fb29a4ba0da78edbf83f88dce1 Mon Sep 17 00:00:00 2001 From: simon Date: Thu, 10 May 2001 08:34:20 +0000 Subject: [PATCH] RDB's Unicode patch. Fonts are now used in Unicode mode where possible and we have a single unified means of trying to display any Unicode code point. Instead of the various ad-hoc translation modes we had before, we now have a single `codepage' option which allows us to treat the incoming (and outgoing) text as any given character set, and locally we map that to Unicode and back. git-svn-id: svn://svn.tartarus.org/sgt/putty@1110 cda61777-01e9-0310-a592-d414129be87e --- Makefile | 2 +- ldisc.c | 4 +- putty.h | 118 +++++-- settings.c | 11 +- terminal.c | 1090 +++++++++++++++++++++++++++++++++++++++++++++--------------- unicode.c | 982 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ wcwidth.c | 190 +++++++++++ windlg.c | 84 +++-- window.c | 862 +++++++++++++++++++++++++++-------------------- xlat.c | 233 ------------- 10 files changed, 2614 insertions(+), 962 deletions(-) create mode 100644 unicode.c create mode 100644 wcwidth.c delete mode 100644 xlat.c diff --git a/Makefile b/Makefile index 07135ffd..7b2122fa 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ RES=res ##-- objects putty puttytel GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ) -GOBJS2 = xlat.$(OBJ) sizetip.$(OBJ) +GOBJS2 = sizetip.$(OBJ) wcwidth.$(OBJ) unicode.$(OBJ) ##-- objects putty puttytel plink LOBJS1 = telnet.$(OBJ) raw.$(OBJ) rlogin.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ) ##-- objects putty plink diff --git a/ldisc.c b/ldisc.c index b307d4e1..48fbe172 100644 --- a/ldisc.c +++ b/ldisc.c @@ -28,7 +28,7 @@ static int term_buflen = 0, term_bufsiz = 0, term_quotenext = 0; static int plen(unsigned char c) { - if ((c >= 32 && c <= 126) || (c >= 160)) + if ((c >= 32 && c <= 126) || (c >= 160 && !utf)) return 1; else if (c < 128) return 2; /* ^x for some x */ @@ -38,7 +38,7 @@ static int plen(unsigned char c) static void pwrite(unsigned char c) { - if ((c >= 32 && c <= 126) || (c >= 160)) { + if ((c >= 32 && c <= 126) || (c >= 160 && !utf)) { c_write(&c, 1); } else if (c < 128) { char cc[2]; diff --git a/putty.h b/putty.h index ee6a2b73..f665f317 100644 --- a/putty.h +++ b/putty.h @@ -20,39 +20,69 @@ #define GLOBAL extern #endif -#define ATTR_ACTCURS 0x80000000UL /* active cursor (block) */ -#define ATTR_PASCURS 0x40000000UL /* passive cursor (box) */ -#define ATTR_INVALID 0x20000000UL -#define ATTR_WRAPPED 0x10000000UL -#define ATTR_RIGHTCURS 0x10000000UL /* doubles as cursor-on-RHS indicator */ +/* Three attribute types: + * The ATTRs (normal attributes) are stored with the characters in the main + * display arrays + * + * The TATTRs (temporary attributes) are generated on the fly, they can overlap + * with characters but not with normal attributes. + * + * The LATTRs (line attributes) conflict with no others and only have one + * value per line. But on area clears the LATTR cells are set to the erase_char + * (or DEFAULT_ATTR + 'E') + * + * ATTR_INVALID is an illegal colour combination. + */ + +#define TATTR_ACTCURS 0x4UL /* active cursor (block) */ +#define TATTR_PASCURS 0x2UL /* passive cursor (box) */ +#define TATTR_RIGHTCURS 0x1UL /* cursor-on-RHS */ #define LATTR_NORM 0x00000000UL #define LATTR_WIDE 0x01000000UL #define LATTR_TOP 0x02000000UL #define LATTR_BOT 0x03000000UL #define LATTR_MODE 0x03000000UL - -#define ATTR_ASCII 0x00000000UL /* normal ASCII charset ESC ( B */ -#define ATTR_GBCHR 0x00100000UL /* UK variant charset ESC ( A */ -#define ATTR_LINEDRW 0x00200000UL /* line drawing charset ESC ( 0 */ - -#define ATTR_BOLD 0x00000100UL -#define ATTR_UNDER 0x00000200UL -#define ATTR_REVERSE 0x00000400UL -#define ATTR_BLINK 0x00000800UL -#define ATTR_FGMASK 0x0000F000UL -#define ATTR_BGMASK 0x000F0000UL -#define ATTR_FGSHIFT 12 -#define ATTR_BGSHIFT 16 - -#define ATTR_DEFAULT 0x00098000UL -#define ATTR_DEFFG 0x00008000UL -#define ATTR_DEFBG 0x00090000UL -#define ATTR_CUR_XOR 0x000BA000UL +#define LATTR_WRAPPED 0x10000000UL + +#define ATTR_INVALID 0x00FF0000UL + +/* Like Linux use the F000 page for direct to font. */ +#define ATTR_OEMCP 0x0000F000UL /* OEM Codepage DTF */ +#define ATTR_ACP 0x0000F100UL /* Ansi Codepage DTF */ + +/* These are internal use overlapping with the UTF-16 surrogates */ +#define ATTR_ASCII 0x0000D800UL /* normal ASCII charset ESC ( B */ +#define ATTR_LINEDRW 0x0000D900UL /* line drawing charset ESC ( 0 */ +#define ATTR_GBCHR 0x0000DB00UL /* UK variant charset ESC ( A */ +#define CSET_MASK 0x0000FF00UL /* Character set mask; MUST be 0xFF00 */ + +#define DIRECT_CHAR(c) ((c&0xFC00)==0xD800) +#define DIRECT_FONT(c) ((c&0xFE00)==0xF000) + +#define UCSERR (ATTR_LINEDRW|'a') /* UCS Format error character. */ +#define UCSWIDE 0x303F + +#define ATTR_WIDE 0x10000000UL +#define ATTR_BOLD 0x01000000UL +#define ATTR_UNDER 0x02000000UL +#define ATTR_REVERSE 0x04000000UL +#define ATTR_BLINK 0x08000000UL +#define ATTR_FGMASK 0x000F0000UL +#define ATTR_BGMASK 0x00F00000UL +#define ATTR_COLOURS 0x00FF0000UL +#define ATTR_FGSHIFT 16 +#define ATTR_BGSHIFT 20 + +#define ATTR_DEFAULT 0x00980000UL +#define ATTR_DEFFG 0x00080000UL +#define ATTR_DEFBG 0x00900000UL #define ERASE_CHAR (ATTR_DEFAULT | ' ') #define ATTR_MASK 0xFFFFFF00UL #define CHAR_MASK 0x000000FFUL -#define CSET_MASK 0x00F00000UL /* mask for character set */ + +#define ATTR_CUR_AND (~(ATTR_BOLD|ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS)) +#define ATTR_CUR_XOR 0x00BA0000UL typedef HDC Context; #define SEL_NL { 13, 10 } @@ -83,6 +113,19 @@ GLOBAL int seen_disp_event; GLOBAL int session_closed; +GLOBAL int big_cursor; + +GLOBAL int utf; +GLOBAL int dbcs_screenfont; +GLOBAL int font_codepage; +GLOBAL int kbd_codepage; +GLOBAL int line_codepage; +GLOBAL WCHAR unitab_line[256]; +GLOBAL WCHAR unitab_font[256]; +GLOBAL WCHAR unitab_xterm[256]; +GLOBAL WCHAR unitab_oemcp[256]; +GLOBAL unsigned char unitab_ctrl[256]; + #define LGXF_OVR 1 /* existing logfile overwrite */ #define LGXF_APN 0 /* existing logfile append */ #define LGXF_ASK -1 /* existing logfile ask */ @@ -123,7 +166,7 @@ typedef enum { } Mouse_Action; typedef enum { - VT_XWINDOWS, VT_OEMANSI, VT_OEMONLY, VT_POORMAN + VT_XWINDOWS, VT_OEMANSI, VT_OEMONLY, VT_POORMAN, VT_UNICODE } VT_Mode; enum { @@ -260,10 +303,7 @@ typedef struct { short wordness[256]; /* translations */ VT_Mode vtmode; - int xlat_enablekoiwin; - int xlat_88592w1250; - int xlat_88592cp852; - int xlat_capslockcyr; + char line_codepage[32]; /* X11 forwarding */ int x11_forward; char x11_display[128]; @@ -310,6 +350,7 @@ struct RSAKey; /* be a little careful of scope */ */ void request_resize(int, int, int); void do_text(Context, int, int, char *, int, unsigned long, int); +void do_cursor(Context, int, int, char *, int, unsigned long, int); void set_title(char *); void set_icon(char *); void set_sbar(int, int, int); @@ -317,8 +358,9 @@ Context get_ctx(void); void free_ctx(Context); void palette_set(int, int, int, int); void palette_reset(void); -void write_clip(void *, int, int); -void get_clip(void **, int *); +void write_aclip(char *, int, int); +void write_clip(wchar_t *, int, int); +void get_clip(wchar_t **, int *); void optimised_move(int, int, int); void set_raw_mouse_mode(int); Mouse_Button translate_button(Mouse_Button b); @@ -448,11 +490,17 @@ void UpdateSizeTip(HWND src, int cx, int cy); void EnableSizeTip(int bEnable); /* - * Exports from xlat.c. + * Exports from unicode.c. */ -unsigned char xlat_kbd2tty(unsigned char c); -unsigned char xlat_tty2scr(unsigned char c); -unsigned char xlat_latkbd2win(unsigned char c); +#ifndef CP_UTF8 +#define CP_UTF8 65001 +#endif +void init_ucs_tables(void); +void lpage_send(int codepage, char *buf, int len); +void luni_send(wchar_t * widebuf, int len); +int check_compose(int first, int second); +int decode_codepage(char *cp_name); +char *cp_name(int codepage); /* * Exports from mscrypto.c diff --git a/settings.c b/settings.c index 44939662..35fe4366 100644 --- a/settings.c +++ b/settings.c @@ -150,10 +150,7 @@ void save_settings(char *section, int do_host, Config * cfg) } write_setting_s(sesskey, buf, buf2); } - write_setting_i(sesskey, "KoiWinXlat", cfg->xlat_enablekoiwin); - write_setting_i(sesskey, "88592Xlat", cfg->xlat_88592w1250); - write_setting_i(sesskey, "88592-CP852", cfg->xlat_88592cp852); - write_setting_i(sesskey, "CapsLockCyr", cfg->xlat_capslockcyr); + write_setting_s(sesskey, "LineCodePage", cfg->line_codepage); write_setting_i(sesskey, "ScrollBar", cfg->scrollbar); write_setting_i(sesskey, "ScrollOnKey", cfg->scroll_on_key); write_setting_i(sesskey, "ScrollOnDisp", cfg->scroll_on_disp); @@ -353,10 +350,8 @@ void load_settings(char *section, int do_host, Config * cfg) cfg->wordness[j] = atoi(q); } } - gppi(sesskey, "KoiWinXlat", 0, &cfg->xlat_enablekoiwin); - gppi(sesskey, "88592Xlat", 0, &cfg->xlat_88592w1250); - gppi(sesskey, "88592-CP852", 0, &cfg->xlat_88592cp852); - gppi(sesskey, "CapsLockCyr", 0, &cfg->xlat_capslockcyr); + gpps(sesskey, "LineCodePage", "", cfg->line_codepage, + sizeof(cfg->line_codepage)); gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar); gppi(sesskey, "ScrollOnKey", 0, &cfg->scroll_on_key); gppi(sesskey, "ScrollOnDisp", 1, &cfg->scroll_on_disp); diff --git a/terminal.c b/terminal.c index 1fb7fced..9abb8483 100644 --- a/terminal.c +++ b/terminal.c @@ -9,6 +9,8 @@ #include "putty.h" #include "tree234.h" +#define VT52_PLUS + #define CL_ANSIMIN 0x0001 /* Codes in all ANSI like terminals. */ #define CL_VT100 0x0002 /* VT100 */ #define CL_VT100AVO 0x0004 /* VT100 +AVO; 132x24 (not 132x14) & attrs */ @@ -54,7 +56,8 @@ static int disptop; /* distance scrolled back (0 or -ve) */ static unsigned long *cpos; /* cursor position (convenience) */ static unsigned long *disptext; /* buffer of text on real screen */ -static unsigned long *wanttext; /* buffer of text we want on screen */ +static unsigned long *dispcurs; /* location of cursor on real screen */ +static unsigned long curstype; /* type of cursor on real screen */ #define VBELL_TIMEOUT 100 /* millisecond len of visual bell */ @@ -67,8 +70,6 @@ int nbeeps; int beep_overloaded; long lastbeep; -static unsigned char *selspace; /* buffer for building selections in */ - #define TSIZE (sizeof(unsigned long)) #define fix_cpos do { cpos = lineptr(curs.y) + curs.x; } while(0) @@ -103,6 +104,10 @@ static int tblinker; /* When the blinking text is on */ static int blink_is_real; /* Actually blink blinking text */ static int term_echoing; /* Does terminal want local echo? */ static int term_editing; /* Does terminal want local edit? */ +static int vt52_bold; /* Force bold on non-bold colours */ +static int utf_state; /* Is there a pending UTF-8 character */ +static int utf_char; /* and what is it so far. */ +static int utf_size; /* The size of the UTF character. */ static int xterm_mouse; /* send mouse messages to app */ @@ -142,14 +147,13 @@ static enum { DO_CTRLS, - IGNORE_NEXT, - SET_GL, SET_GR, SEEN_OSC_P, OSC_STRING, OSC_MAYBE_ST, - SEEN_ESCHASH, VT52_ESC, VT52_Y1, - VT52_Y2 + VT52_Y2, + VT52_FG, + VT52_BG } termstate; static enum { @@ -179,8 +183,9 @@ static short wordness[256] = { 2, 2, 2, 2, 2, 2, 2, 2, /* EF */ }; -static unsigned char sel_nl[] = SEL_NL; -static char *paste_buffer = 0; +#define sel_nl_sz (sizeof(sel_nl)/sizeof(wchar_t)) +static wchar_t sel_nl[] = SEL_NL; +static wchar_t *paste_buffer = 0; static int paste_len, paste_pos, paste_hold; /* @@ -262,6 +267,7 @@ static void power_on(void) rvideo = 0; in_vbell = FALSE; cursor_on = 1; + big_cursor = 0; save_attr = curr_attr = ATTR_DEFAULT; term_editing = term_echoing = FALSE; ldisc_send(NULL, 0); /* cause ldisc to notice changes */ @@ -336,9 +342,8 @@ void term_init(void) { screen = alt_screen = scrollback = NULL; disptop = 0; - disptext = wanttext = NULL; + disptext = dispcurs = NULL; tabs = NULL; - selspace = NULL; deselect(); rows = cols = -1; power_on(); @@ -354,7 +359,7 @@ void term_init(void) void term_size(int newrows, int newcols, int newsavelines) { tree234 *newsb, *newscreen, *newalt; - unsigned long *newdisp, *newwant, *oldline, *line; + unsigned long *newdisp, *oldline, *line; int i, j, ccols; int sblen; int save_alt_which = alt_which; @@ -426,12 +431,7 @@ void term_size(int newrows, int newcols, int newsavelines) newdisp[i] = ATTR_INVALID; sfree(disptext); disptext = newdisp; - - newwant = smalloc(newrows * (newcols + 1) * TSIZE); - for (i = 0; i < newrows * (newcols + 1); i++) - newwant[i] = ATTR_INVALID; - sfree(wanttext); - wanttext = newwant; + dispcurs = NULL; newalt = newtree234(NULL); for (i = 0; i < newrows; i++) { @@ -448,10 +448,6 @@ void term_size(int newrows, int newcols, int newsavelines) } alt_screen = newalt; - sfree(selspace); - selspace = - smalloc((newrows + newsavelines) * (newcols + sizeof(sel_nl))); - tabs = srealloc(tabs, newcols * sizeof(*tabs)); { int i; @@ -731,7 +727,7 @@ static void erase_lots(int line_only, int from_begin, int to_end) ldata = lineptr(start.y); while (poslt(start, end)) { if (start.y == cols && !erase_lattr) - ldata[start.x] &= ~ATTR_WRAPPED; + ldata[start.x] &= ~LATTR_WRAPPED; else ldata[start.x] = erase_char; if (incpos(start) && start.y < rows) @@ -784,6 +780,12 @@ static void toggle_mode(int mode, int query, int state) break; case 2: /* VT52 mode */ vt52_mode = !state; + if (vt52_mode) { + blink_is_real = FALSE; + vt52_bold = FALSE; + } else { + blink_is_real = cfg.blinktext; + } break; case 3: /* 80/132 columns */ deselect(); @@ -857,6 +859,9 @@ static void toggle_mode(int mode, int query, int state) case 20: /* Return sends ... */ cr_lf_return = state; break; + case 34: /* Make cursor BIG */ + compatibility2(OTHER, VT220); + big_cursor = !state; } } @@ -907,8 +912,149 @@ void term_out(void) * be able to display 8-bit characters, but I'll let that go 'cause * of i18n. */ - if (((c & 0x60) == 0 || c == '\177') && - termstate < DO_CTRLS && ((c & 0x80) == 0 || has_compat(VT220))) { + + /* First see about all those translations. */ + if (termstate == TOPLEVEL) { + if (utf) + switch (utf_state) { + case 0: + if (c < 0x80) { + /* I know; gotos are evil. This one is really bad! + * But before you try removing it follow the path of the + * sequence "0x5F 0xC0 0x71" with UTF and VTGraphics on. + */ + /* + if (cfg.no_vt_graph_with_utf8) break; + */ + goto evil_jump; + } else if ((c & 0xe0) == 0xc0) { + utf_size = utf_state = 1; + utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + utf_size = utf_state = 2; + utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + utf_size = utf_state = 3; + utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + utf_size = utf_state = 4; + utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + utf_size = utf_state = 5; + utf_char = (c & 0x01); + } else { + c = UCSERR; + break; + } + continue; + case 1: + case 2: + case 3: + case 4: + case 5: + if ((c & 0xC0) != 0x80) { + inbuf_reap--; /* This causes the faulting character */ + c = UCSERR; /* to be logged twice - not really a */ + utf_state = 0; /* serious problem. */ + break; + } + utf_char = (utf_char << 6) | (c & 0x3f); + if (--utf_state) + continue; + + c = utf_char; + + /* Is somebody trying to be evil! */ + if (c < 0x80 || + (c < 0x800 && utf_size >= 2) || + (c < 0x10000 && utf_size >= 3) || + (c < 0x200000 && utf_size >= 4) || + (c < 0x4000000 && utf_size >= 5)) + c = UCSERR; + + /* Unicode line separator and paragraph separator are CR-LF */ + if (c == 0x2028 || c == 0x2029) + c = 0x85; + + /* High controls are probably a Baaad idea too. */ + if (c < 0xA0) + c = 0xFFFD; + + /* The UTF-16 surrogates are not nice either. */ + /* The standard give the option of decoding these: + * I don't want to! */ + if (c >= 0xD800 && c < 0xE000) + c = UCSERR; + + /* ISO 10646 characters now limited to UTF-16 range. */ + if (c > 0x10FFFF) + c = UCSERR; + + /* This is currently a TagPhobic application.. */ + if (c >= 0xE0000 && c <= 0xE007F) + continue; + + /* U+FEFF is best seen as a null. */ + if (c == 0xFEFF) + continue; + /* But U+FFFE is an error. */ + if (c == 0xFFFE || c == 0xFFFF) + c = UCSERR; + + /* Oops this is a 16bit implementation */ + if (c >= 0x10000) + c = 0xFFFD; + break; + } else { + evil_jump:; + switch (cset_attr[cset]) { + /* + * Linedraw characters are different from 'ESC ( B' + * only for a small range. For ones outside that + * range, make sure we use the same font as well as + * the same encoding. + */ + case ATTR_LINEDRW: + if (unitab_ctrl[c] != 0xFF) + c = unitab_ctrl[c]; + else + c = ((unsigned char) c) | ATTR_LINEDRW; + break; + + case ATTR_GBCHR: + /* If UK-ASCII, make the '#' a LineDraw Pound */ + if (c == '#') { + c = '}' | ATTR_LINEDRW; + break; + } + /*FALLTHROUGH*/ case ATTR_ASCII: + if (unitab_ctrl[c] != 0xFF) + c = unitab_ctrl[c]; + else + c = ((unsigned char) c) | ATTR_ASCII; + break; + } + } + } + + /* How about C1 controls ? */ + if ((c & -32) == 0x80 && termstate < DO_CTRLS && !vt52_mode && + has_compat(VT220)) { + termstate = SEEN_ESC; + esc_query = FALSE; + c = '@' + (c & 0x1F); + } + + /* Or the GL control. */ + if (c == '\177' && termstate < DO_CTRLS && has_compat(OTHER)) { + if (curs.x && !wrapnext) + curs.x--; + wrapnext = FALSE; + fix_cpos; + *cpos = (' ' | curr_attr | ATTR_ASCII); + } else + /* Or normal C0 controls. */ + if ((c & -32) == 0 && termstate < DO_CTRLS) { switch (c) { case '\005': /* terminal type query */ /* Strictly speaking this is VT100 but a VT100 defaults to @@ -936,9 +1082,9 @@ void term_out(void) } else if (*s == '^') { state = 1; } else - *d++ = xlat_kbd2tty((unsigned char) *s); + *d++ = *s; } - ldisc_send(abuf, d - abuf); + lpage_send(CP_ACP, abuf, d - abuf); } break; case '\007': @@ -1034,20 +1180,9 @@ void term_out(void) else { compatibility(ANSIMIN); termstate = SEEN_ESC; + esc_query = FALSE; } break; - case 0233: - compatibility(VT220); - termstate = SEEN_CSI; - esc_nargs = 1; - esc_args[0] = ARG_DEFAULT; - esc_query = FALSE; - break; - case 0235: - compatibility(VT220); - termstate = SEEN_OSC; - esc_args[0] = 0; - break; case '\r': curs.x = 0; wrapnext = FALSE; @@ -1102,22 +1237,13 @@ void term_out(void) } seen_disp_event = TRUE; break; - case '\177': /* Destructive backspace - This does nothing on a real VT100 */ - compatibility(OTHER); - if (curs.x && !wrapnext) - curs.x--; - wrapnext = FALSE; - fix_cpos; - *cpos = (' ' | curr_attr | ATTR_ASCII); - break; } } else switch (termstate) { case TOPLEVEL: /* Only graphic characters get this far, ctrls are stripped above */ if (wrapnext && wrap) { - cpos[1] |= ATTR_WRAPPED; + cpos[1] |= LATTR_WRAPPED; if (curs.y == marg_b) scroll(marg_t, marg_b, 1, TRUE); else if (curs.y < rows - 1) @@ -1133,49 +1259,49 @@ void term_out(void) incpos(cursplus); check_selection(curs, cursplus); } - switch (cset_attr[cset]) { - /* - * Linedraw characters are different from 'ESC ( B' - * only for a small range. For ones outside that - * range, make sure we use the same font as well as - * the same encoding. - */ - case ATTR_LINEDRW: - if (c < 0x5f || c > 0x7F) - *cpos++ = - xlat_tty2scr((unsigned char) c) | curr_attr | - ATTR_ASCII; - else if (c == 0x5F) - *cpos++ = ' ' | curr_attr | ATTR_ASCII; - else - *cpos++ = - ((unsigned char) c) | curr_attr | ATTR_LINEDRW; - break; - case ATTR_GBCHR: - /* If UK-ASCII, make the '#' a LineDraw Pound */ - if (c == '#') { - *cpos++ = '}' | curr_attr | ATTR_LINEDRW; + if ((c & CSET_MASK) == ATTR_ASCII || (c & CSET_MASK) == 0) + logtraffic((unsigned char) c, LGTYP_ASCII); + { + extern int wcwidth(wchar_t ucs); + int width = 0; + if (DIRECT_CHAR(c)) + width = 1; + if (!width) + width = wcwidth((wchar_t) c); + switch (width) { + case 2: + if (curs.x + 1 != cols) { + *cpos++ = c | ATTR_WIDE | curr_attr; + *cpos++ = UCSWIDE | curr_attr; + curs.x++; + break; + } + case 1: + *cpos++ = c | curr_attr; break; + default: + continue; } - /*FALLTHROUGH*/ default: - *cpos = xlat_tty2scr((unsigned char) c) | curr_attr | - (c <= 0x7F ? cset_attr[cset] : ATTR_ASCII); - logtraffic((unsigned char) c, LGTYP_ASCII); - cpos++; - break; } curs.x++; if (curs.x == cols) { cpos--; curs.x--; wrapnext = TRUE; + if (wrap && vt52_mode) { + cpos[1] |= LATTR_WRAPPED; + if (curs.y == marg_b) + scroll(marg_t, marg_b, 1, TRUE); + else if (curs.y < rows - 1) + curs.y++; + curs.x = 0; + fix_cpos; + wrapnext = FALSE; + } } seen_disp_event = 1; break; - case IGNORE_NEXT: - termstate = TOPLEVEL; - break; case OSC_MAYBE_ST: /* * This state is virtually identical to SEEN_ESC, with the @@ -1189,12 +1315,15 @@ void term_out(void) } /* else fall through */ case SEEN_ESC: - termstate = TOPLEVEL; - switch (c) { - case ' ': /* some weird sequence? */ - compatibility(VT220); - termstate = IGNORE_NEXT; + if (c >= ' ' && c <= '/') { + if (esc_query) + esc_query = -1; + else + esc_query = c; break; + } + termstate = TOPLEVEL; + switch (ANSI(c, esc_query)) { case '[': /* enter CSI mode */ termstate = SEEN_CSI; esc_nargs = 1; @@ -1207,14 +1336,6 @@ void term_out(void) termstate = SEEN_OSC; esc_args[0] = 0; break; - case '(': /* should set GL */ - compatibility(VT100); - termstate = SET_GL; - break; - case ')': /* should set GR */ - compatibility(VT100); - termstate = SET_GR; - break; case '7': /* save cursor */ compatibility(VT100); save_cursor(TRUE); @@ -1278,14 +1399,97 @@ void term_out(void) disptop = 0; seen_disp_event = TRUE; break; - case '#': /* ESC # 8 fills screen with Es :-) */ - compatibility(VT100); - termstate = SEEN_ESCHASH; - break; case 'H': /* set a tab */ compatibility(VT100); tabs[curs.x] = TRUE; break; + + case ANSI('8', '#'): /* ESC # 8 fills screen with Es :-) */ + compatibility(VT100); + { + unsigned long *ldata; + int i, j; + pos scrtop, scrbot; + + for (i = 0; i < rows; i++) { + ldata = lineptr(i); + for (j = 0; j < cols; j++) + ldata[j] = ATTR_DEFAULT | 'E'; + ldata[cols] = 0; + } + disptop = 0; + seen_disp_event = TRUE; + scrtop.x = scrtop.y = 0; + scrbot.x = 0; + scrbot.y = rows; + check_selection(scrtop, scrbot); + } + break; + + case ANSI('3', '#'): + case ANSI('4', '#'): + case ANSI('5', '#'): + case ANSI('6', '#'): + compatibility(VT100); + { + unsigned long nlattr; + unsigned long *ldata; + switch (ANSI(c, esc_query)) { + case ANSI('3', '#'): + nlattr = LATTR_TOP; + break; + case ANSI('4', '#'): + nlattr = LATTR_BOT; + break; + case ANSI('5', '#'): + nlattr = LATTR_NORM; + break; + case ANSI('6', '#'): + nlattr = LATTR_WIDE; + break; + } + ldata = lineptr(curs.y); + ldata[cols] &= ~LATTR_MODE; + ldata[cols] |= nlattr; + } + break; + + case ANSI('A', '('): + compatibility(VT100); + cset_attr[0] = ATTR_GBCHR; + break; + case ANSI('B', '('): + compatibility(VT100); + cset_attr[0] = ATTR_ASCII; + break; + case ANSI('0', '('): + compatibility(VT100); + cset_attr[0] = ATTR_LINEDRW; + break; + + case ANSI('A', ')'): + compatibility(VT100); + cset_attr[1] = ATTR_GBCHR; + break; + case ANSI('B', ')'): + compatibility(VT100); + cset_attr[1] = ATTR_ASCII; + break; + case ANSI('0', ')'): + compatibility(VT100); + cset_attr[1] = ATTR_LINEDRW; + break; + + case ANSI('8', '%'): /* Old Linux code */ + case ANSI('G', '%'): + compatibility(OTHER); + utf = 1; + break; + case ANSI('@', '%'): + compatibility(OTHER); + if (line_codepage != CP_UTF8) + utf = 0; + break; } break; case SEEN_CSI: @@ -1502,11 +1706,9 @@ void term_out(void) * this was selected by CSI 7m. * * case 2: - * This is DIM on the VT100-AVO and VT102 - * case 5: - * This is BLINK on the VT100-AVO and VT102+ + * This is sometimes DIM, eg on the GIGI and Linux * case 8: - * This is INVIS on the VT100-AVO and VT102 + * This is sometimes INVIS various ANSI. * case 21: * This like 22 disables BOLD, DIM and INVIS * @@ -1711,7 +1913,7 @@ void term_out(void) * This first appeared in the VT220, but we do need to get * back to PuTTY mode so I won't check it. * - * The arg in 40..42 are a PuTTY extension. + * The arg in 40..42,50 are a PuTTY extension. * The 2nd arg, 8bit vs 7bit is not checked. * * Setting VT102 mode should also change the Fkeys to @@ -1781,24 +1983,6 @@ void term_out(void) break; } break; - case SET_GL: - case SET_GR: - /* VT100 only here, checked above */ - switch (c) { - case 'A': - cset_attr[termstate == SET_GL ? 0 : 1] = ATTR_GBCHR; - break; - case '0': - cset_attr[termstate == SET_GL ? 0 : 1] = ATTR_LINEDRW; - break; - case 'B': - default: /* specifically, 'B' */ - cset_attr[termstate == SET_GL ? 0 : 1] = ATTR_ASCII; - break; - } - if (!has_compat(VT220) || c != '%') - termstate = TOPLEVEL; - break; case SEEN_OSC: osc_w = FALSE; switch (c) { @@ -1912,55 +2096,6 @@ void term_out(void) osc_strlen = 0; } break; - case SEEN_ESCHASH: - { - unsigned long nlattr; - unsigned long *ldata; - int i, j; - pos scrtop, scrbot; - - switch (c) { - case '8': - for (i = 0; i < rows; i++) { - ldata = lineptr(i); - for (j = 0; j < cols; j++) - ldata[j] = ATTR_DEFAULT | 'E'; - ldata[cols] = 0; - } - disptop = 0; - seen_disp_event = TRUE; - scrtop.x = scrtop.y = 0; - scrbot.x = 0; - scrbot.y = rows; - check_selection(scrtop, scrbot); - break; - - case '3': - case '4': - case '5': - case '6': - switch (c) { - case '3': - nlattr = LATTR_TOP; - break; - case '4': - nlattr = LATTR_BOT; - break; - case '5': - nlattr = LATTR_NORM; - break; - case '6': - nlattr = LATTR_WIDE; - break; - } - - ldata = lineptr(curs.y); - ldata[cols] &= ~LATTR_MODE; - ldata[cols] |= nlattr; - } - } - termstate = TOPLEVEL; - break; case VT52_ESC: termstate = TOPLEVEL; seen_disp_event = TRUE; @@ -1977,6 +2112,46 @@ void term_out(void) case 'D': move(curs.x - 1, curs.y, 1); break; + /* + * From the VT100 Manual + * NOTE: The special graphics characters in the VT100 + * are different from those in the VT52 + * + * From VT102 manual: + * 137 _ Blank - Same + * 140 ` Reserved - Humm. + * 141 a Solid rectangle - Similar + * 142 b 1/ - Top half of fraction for the + * 143 c 3/ - subscript numbers below. + * 144 d 5/ + * 145 e 7/ + * 146 f Degrees - Same + * 147 g Plus or minus - Same + * 150 h Right arrow + * 151 i Ellipsis (dots) + * 152 j Divide by + * 153 k Down arrow + * 154 l Bar at scan 0 + * 155 m Bar at scan 1 + * 156 n Bar at scan 2 + * 157 o Bar at scan 3 - Similar + * 160 p Bar at scan 4 - Similar + * 161 q Bar at scan 5 - Similar + * 162 r Bar at scan 6 - Same + * 163 s Bar at scan 7 - Similar + * 164 t Subscript 0 + * 165 u Subscript 1 + * 166 v Subscript 2 + * 167 w Subscript 3 + * 170 x Subscript 4 + * 171 y Subscript 5 + * 172 z Subscript 6 + * 173 { Subscript 7 + * 174 | Subscript 8 + * 175 } Subscript 9 + * 176 ~ Paragraph + * + */ case 'F': cset_attr[cset = 0] = ATTR_LINEDRW; break; @@ -2001,6 +2176,7 @@ void term_out(void) case 'K': erase_lots(TRUE, FALSE, TRUE); break; +#if 0 case 'V': /* XXX Print cursor line */ break; @@ -2010,6 +2186,7 @@ void term_out(void) case 'X': /* XXX Stop controller mode */ break; +#endif case 'Y': termstate = VT52_Y1; break; @@ -2028,7 +2205,9 @@ void term_out(void) * emulation. */ vt52_mode = FALSE; + blink_is_real = cfg.blinktext; break; +#if 0 case '^': /* XXX Enter auto print mode */ break; @@ -2038,6 +2217,105 @@ void term_out(void) case ']': /* XXX Print screen */ break; +#endif + +#ifdef VT52_PLUS + case 'E': + /* compatibility(ATARI) */ + move(0, 0, 0); + erase_lots(FALSE, FALSE, TRUE); + disptop = 0; + break; + case 'L': + /* compatibility(ATARI) */ + if (curs.y <= marg_b) + scroll(curs.y, marg_b, -1, FALSE); + break; + case 'M': + /* compatibility(ATARI) */ + if (curs.y <= marg_b) + scroll(curs.y, marg_b, 1, TRUE); + break; + case 'b': + /* compatibility(ATARI) */ + termstate = VT52_FG; + break; + case 'c': + /* compatibility(ATARI) */ + termstate = VT52_BG; + break; + case 'd': + /* compatibility(ATARI) */ + erase_lots(FALSE, TRUE, FALSE); + disptop = 0; + break; + case 'e': + /* compatibility(ATARI) */ + cursor_on = TRUE; + break; + case 'f': + /* compatibility(ATARI) */ + cursor_on = FALSE; + break; + /* case 'j': Save cursor position - broken on ST */ + /* case 'k': Restore cursor position */ + case 'l': + /* compatibility(ATARI) */ + erase_lots(TRUE, TRUE, TRUE); + curs.x = 0; + wrapnext = FALSE; + fix_cpos; + break; + case 'o': + /* compatibility(ATARI) */ + erase_lots(TRUE, TRUE, FALSE); + break; + case 'p': + /* compatibility(ATARI) */ + curr_attr |= ATTR_REVERSE; + break; + case 'q': + /* compatibility(ATARI) */ + curr_attr &= ~ATTR_REVERSE; + break; + case 'v': /* wrap Autowrap on - Wyse style */ + /* compatibility(ATARI) */ + wrap = 1; + break; + case 'w': /* Autowrap off */ + /* compatibility(ATARI) */ + wrap = 0; + break; + + case 'R': + /* compatibility(OTHER) */ + vt52_bold = FALSE; + curr_attr = ATTR_DEFAULT; + if (use_bce) + erase_char = (' ' | + (curr_attr & + (ATTR_FGMASK | ATTR_BGMASK | + ATTR_BLINK))); + break; + case 'S': + /* compatibility(VI50) */ + curr_attr |= ATTR_UNDER; + break; + case 'W': + /* compatibility(VI50) */ + curr_attr &= ~ATTR_UNDER; + break; + case 'U': + /* compatibility(VI50) */ + vt52_bold = TRUE; + curr_attr |= ATTR_BOLD; + break; + case 'T': + /* compatibility(VI50) */ + vt52_bold = FALSE; + curr_attr &= ~ATTR_BOLD; + break; +#endif } break; case VT52_Y1: @@ -2048,6 +2326,39 @@ void term_out(void) termstate = TOPLEVEL; move(c - ' ', curs.y, 0); break; + +#ifdef VT52_PLUS + case VT52_FG: + termstate = TOPLEVEL; + curr_attr &= ~ATTR_FGMASK; + curr_attr &= ~ATTR_BOLD; + curr_attr |= (c & 0x7) << ATTR_FGSHIFT; + if ((c & 0x8) || vt52_bold) + curr_attr |= ATTR_BOLD; + + if (use_bce) + erase_char = (' ' | + (curr_attr & + (ATTR_FGMASK | ATTR_BGMASK | + ATTR_BLINK))); + break; + case VT52_BG: + termstate = TOPLEVEL; + curr_attr &= ~ATTR_BGMASK; + curr_attr &= ~ATTR_BLINK; + curr_attr |= (c & 0x7) << ATTR_BGSHIFT; + + /* Note: bold background */ + if (c & 0x8) + curr_attr |= ATTR_BLINK; + + if (use_bce) + erase_char = (' ' | + (curr_attr & + (ATTR_FGMASK | ATTR_BGMASK | + ATTR_BLINK))); + break; +#endif } if (selstate != NO_SELECTION) { pos cursplus = curs; @@ -2058,6 +2369,7 @@ void term_out(void) inbuf_head = 0; } +#if 0 /* * Compare two lines to determine whether they are sufficiently * alike to scroll-optimise one to the other. Return the degree of @@ -2071,6 +2383,7 @@ static int linecmp(unsigned long *a, unsigned long *b) n += (*a++ == *b++); return n; } +#endif /* * Given a context, update the window. Out of paranoia, we don't @@ -2078,10 +2391,11 @@ static int linecmp(unsigned long *a, unsigned long *b) */ static void do_paint(Context ctx, int may_optimise) { - int i, j, start, our_curs_y; - unsigned long attr, rv, cursor; + int i, j, our_curs_y; + unsigned long rv, cursor; pos scrpos; char ch[1024]; + long cursor_background = ERASE_CHAR; long ticks; /* @@ -2093,83 +2407,162 @@ static void do_paint(Context ctx, int may_optimise) in_vbell = FALSE; } + rv = (!rvideo ^ !in_vbell ? ATTR_REVERSE : 0); + /* Depends on: * screen array, disptop, scrtop, * selection, rv, * cfg.blinkpc, blink_is_real, tblinker, - * curs.y, curs.x, blinker, cfg.blink_cur, cursor_on, has_focus + * curs.y, curs.x, blinker, cfg.blink_cur, cursor_on, has_focus, wrapnext */ + + /* Has the cursor position or type changed ? */ if (cursor_on) { if (has_focus) { if (blinker || !cfg.blink_cur) - cursor = ATTR_ACTCURS; + cursor = TATTR_ACTCURS; else cursor = 0; } else - cursor = ATTR_PASCURS; + cursor = TATTR_PASCURS; if (wrapnext) - cursor |= ATTR_RIGHTCURS; + cursor |= TATTR_RIGHTCURS; } else cursor = 0; - rv = (!rvideo ^ !in_vbell ? ATTR_REVERSE : 0); our_curs_y = curs.y - disptop; + if (dispcurs && (curstype != cursor || + dispcurs != + disptext + our_curs_y * (cols + 1) + curs.x)) { + if (dispcurs > disptext && (dispcurs[-1] & ATTR_WIDE)) + dispcurs[-1] |= ATTR_INVALID; + if ((*dispcurs & ATTR_WIDE)) + dispcurs[1] |= ATTR_INVALID; + *dispcurs |= ATTR_INVALID; + curstype = 0; + } + dispcurs = NULL; + + /* The normal screen data */ for (i = 0; i < rows; i++) { unsigned long *ldata; int lattr; + int idx, dirty_line, dirty_run; + unsigned long attr = 0; + int updated_line = 0; + int start = 0; + int ccount = 0; + int last_run_dirty = 0; + scrpos.y = i + disptop; ldata = lineptr(scrpos.y); lattr = (ldata[cols] & LATTR_MODE); - for (j = 0; j <= cols; j++) { - unsigned long d = ldata[j]; - int idx = i * (cols + 1) + j; + + idx = i * (cols + 1); + dirty_run = dirty_line = (ldata[cols] != disptext[idx + cols]); + disptext[idx + cols] = ldata[cols]; + + for (j = 0; j < cols; j++, idx++) { + unsigned long tattr, tchar; + unsigned long *d = ldata + j; + int break_run; scrpos.x = j; - wanttext[idx] = lattr | (((d & ~ATTR_WRAPPED) ^ rv - ^ (posle(selstart, scrpos) && - poslt(scrpos, selend) ? - ATTR_REVERSE : 0)) | - (i == our_curs_y - && j == curs.x ? cursor : 0)); - if (blink_is_real) { - if (has_focus && tblinker && (wanttext[idx] & ATTR_BLINK)) { - wanttext[idx] &= ATTR_MASK; - wanttext[idx] += ' '; + tchar = (*d & (CHAR_MASK | CSET_MASK)); + tattr = (*d & (ATTR_MASK ^ CSET_MASK)); + switch (tchar & CSET_MASK) { + case ATTR_ASCII: + tchar = unitab_line[tchar & 0xFF]; + break; + case ATTR_LINEDRW: + tchar = unitab_xterm[tchar & 0xFF]; + break; + } + tattr |= (tchar & CSET_MASK); + tchar &= CHAR_MASK; + + /* Video reversing things */ + tattr = (tattr ^ rv + ^ (posle(selstart, scrpos) && + poslt(scrpos, selend) ? ATTR_REVERSE : 0)); + + /* 'Real' blinking ? */ + if (blink_is_real && (tattr & ATTR_BLINK)) { + if (has_focus && tblinker) { + tchar = ' '; + tattr &= ~CSET_MASK; + tattr |= ATTR_ACP; } - wanttext[idx] &= ~ATTR_BLINK; + tattr &= ~ATTR_BLINK; } - } - } - /* - * We would perform scrolling optimisations in here, if they - * didn't have a nasty tendency to cause the whole sodding - * program to hang for a second at speed-critical moments. - * We'll leave it well alone... - */ + /* Cursor here ? Save the 'background' */ + if (i == our_curs_y && j == curs.x) { + cursor_background = tattr | tchar; + dispcurs = disptext + idx; + } - for (i = 0; i < rows; i++) { - int idx = i * (cols + 1); - int lattr = (wanttext[idx + cols] & LATTR_MODE); - start = -1; - for (j = 0; j <= cols; j++, idx++) { - unsigned long t = wanttext[idx]; - int needs_update = (j < cols && t != disptext[idx]); - int keep_going = (start != -1 && needs_update && - (t & ATTR_MASK) == attr && - j - start < sizeof(ch)); - if (start != -1 && !keep_going) { - do_text(ctx, start, i, ch, j - start, attr, lattr); - start = -1; + if ((disptext[idx] ^ tattr) & ATTR_WIDE) + dirty_line = TRUE; + + break_run = (tattr != attr || j - start >= sizeof(ch)); + + /* Special hack for VT100 Linedraw glyphs */ + if ((attr & CSET_MASK) == 0x2300 && tchar >= 0xBA + && tchar <= 0xBD) break_run = TRUE; + + if (!dbcs_screenfont && !dirty_line) { + if ((tchar | tattr) == disptext[idx]) + break_run = TRUE; + else if (!dirty_run && ccount == 1) + break_run = TRUE; } - if (needs_update) { - if (start == -1) { - start = j; - attr = t & ATTR_MASK; + + if (break_run) { + if ((dirty_run || last_run_dirty) && ccount > 0) { + do_text(ctx, start, i, ch, ccount, attr, lattr); + updated_line = 1; + } + start = j; + ccount = 0; + attr = tattr; + if (dbcs_screenfont) + last_run_dirty = dirty_run; + dirty_run = dirty_line; + } + + if ((tchar | tattr) != disptext[idx]) + dirty_run = TRUE; + ch[ccount++] = (char) tchar; + disptext[idx] = tchar | tattr; + + /* If it's a wide char step along to the next one. */ + if (tattr & ATTR_WIDE) { + if (++j < cols) { + idx++; + d++; + /* Cursor is here ? Ouch! */ + if (i == our_curs_y && j == curs.x) { + cursor_background = *d; + dispcurs = disptext + idx; + } + if (disptext[idx] != *d) + dirty_run = TRUE; + disptext[idx] = *d; } - ch[j - start] = (char) (t & CHAR_MASK); } - disptext[idx] = t; + } + if (dirty_run && ccount > 0) { + do_text(ctx, start, i, ch, ccount, attr, lattr); + updated_line = 1; + } + + /* Cursor on this line ? (and changed) */ + if (i == our_curs_y && (curstype != cursor || updated_line)) { + ch[0] = (char) (cursor_background & CHAR_MASK); + attr = (cursor_background & ATTR_MASK) | cursor; + do_cursor(ctx, curs.x, i, ch, 1, attr, lattr); + curstype = cursor; } } } @@ -2267,17 +2660,16 @@ void term_scroll(int rel, int where) term_update(); } -static void clipme(pos top, pos bottom, char *workbuf) +static void clipme(pos top, pos bottom) { - char *wbptr; /* where next char goes within workbuf */ + wchar_t *workbuf; + wchar_t *wbptr; /* where next char goes within workbuf */ int wblen = 0; /* workbuf len */ int buflen; /* amount of memory allocated to workbuf */ - if (workbuf != NULL) { /* user supplied buffer? */ - buflen = -1; /* assume buffer passed in is big enough */ - wbptr = workbuf; /* start filling here */ - } else - buflen = 0; /* No data is available yet */ + buflen = 5120; /* Default size */ + workbuf = smalloc(buflen * sizeof(wchar_t)); + wbptr = workbuf; /* start filling here */ while (poslt(top, bottom)) { int nl = FALSE; @@ -2287,49 +2679,94 @@ static void clipme(pos top, pos bottom, char *workbuf) nlpos.y = top.y; nlpos.x = cols; - if (!(ldata[cols] & ATTR_WRAPPED)) { - while ((ldata[nlpos.x - 1] & CHAR_MASK) == 0x20 - && poslt(top, nlpos)) decpos(nlpos); + if (!(ldata[cols] & LATTR_WRAPPED)) { + while (((ldata[nlpos.x - 1] & 0xFF) == 0x20 || + (DIRECT_CHAR(ldata[nlpos.x - 1]) && + (ldata[nlpos.x - 1] & CHAR_MASK) == 0x20)) + && poslt(top, nlpos)) + decpos(nlpos); if (poslt(nlpos, bottom)) nl = TRUE; } while (poslt(top, bottom) && poslt(top, nlpos)) { - int ch = (ldata[top.x] & CHAR_MASK); - int set = (ldata[top.x] & CSET_MASK); - - /* VT Specials -> ISO8859-1 for Cut&Paste */ - static const unsigned char poorman2[] = - "* # HTFFCRLF\xB0 \xB1 NLVT+ + + + + - - - - - + + + + | <=>=PI!=\xA3 \xB7 "; - - if (set && !cfg.rawcnp) { - if (set == ATTR_LINEDRW && ch >= 0x60 && ch < 0x7F) { - int x; - if ((x = poorman2[2 * (ch - 0x60) + 1]) == ' ') - x = 0; - ch = (x << 8) + poorman2[2 * (ch - 0x60)]; +#if 0 + char cbuf[16], *p; + sprintf(cbuf, "", (ldata[top.x] & 0xFFFF)); +#else + wchar_t cbuf[16], *p; + int uc = (ldata[top.x] & 0xFFFF); + int set, c; + + if (uc == UCSWIDE) { + top.x++; + continue; + } + + switch (uc & CSET_MASK) { + case ATTR_LINEDRW: + if (!cfg.rawcnp) { + uc = unitab_xterm[uc & 0xFF]; + break; } + case ATTR_ASCII: + uc = unitab_line[uc & 0xFF]; + break; } + switch (uc & CSET_MASK) { + case ATTR_ACP: + uc = unitab_font[uc & 0xFF]; + break; + case ATTR_OEMCP: + uc = unitab_oemcp[uc & 0xFF]; + break; + } + + set = (uc & CSET_MASK); + c = (uc & CHAR_MASK); + cbuf[0] = uc; + cbuf[1] = 0; + + if (DIRECT_FONT(uc)) { + if (c >= ' ' && c != 0x7F) { + unsigned char buf[4]; + WCHAR wbuf[4]; + int rv; + if (IsDBCSLeadByteEx(font_codepage, (BYTE) c)) { + buf[0] = c; + buf[1] = (unsigned char) ldata[top.x + 1]; + rv = MultiByteToWideChar(font_codepage, + 0, buf, 2, wbuf, 4); + top.x++; + } else { + buf[0] = c; + rv = MultiByteToWideChar(font_codepage, + 0, buf, 1, wbuf, 4); + } - while (ch != 0) { - if (cfg.rawcnp || !!(ch & 0xE0)) { - if (wblen == buflen) { - workbuf = srealloc(workbuf, buflen += 100); - wbptr = workbuf + wblen; + if (rv > 0) { + memcpy(cbuf, wbuf, rv * sizeof(wchar_t)); + cbuf[rv] = 0; } - wblen++; - *wbptr++ = (unsigned char) ch; } - ch >>= 8; + } +#endif + + for (p = cbuf; *p; p++) { + /* Enough overhead for trailing NL and nul */ + if (wblen >= buflen - 16) { + workbuf = + srealloc(workbuf, + sizeof(wchar_t) * (buflen += 100)); + wbptr = workbuf + wblen; + } + wblen++; + *wbptr++ = *p; } top.x++; } if (nl) { int i; - for (i = 0; i < sizeof(sel_nl); i++) { - if (wblen == buflen) { - workbuf = srealloc(workbuf, buflen += 100); - wbptr = workbuf + wblen; - } + for (i = 0; i < sel_nl_sz; i++) { wblen++; *wbptr++ = sel_nl[i]; } @@ -2337,17 +2774,122 @@ static void clipme(pos top, pos bottom, char *workbuf) top.y++; top.x = 0; } + wblen++; + *wbptr++ = 0; write_clip(workbuf, wblen, FALSE); /* transfer to clipboard */ if (buflen > 0) /* indicates we allocated this buffer */ sfree(workbuf); - } + void term_copyall(void) { pos top; top.y = -count234(scrollback); top.x = 0; - clipme(top, curs, NULL /* dynamic allocation */ ); + clipme(top, curs); +} + +/* + * The wordness array is mainly for deciding the disposition of the US-ASCII + * characters. + */ +static int wordtype(int uc) +{ + static struct { + int start, end, ctype; + } *wptr, ucs_words[] = { + { + 128, 160, 0}, { + 161, 191, 1}, { + 215, 215, 1}, { + 247, 247, 1}, { + 0x037e, 0x037e, 1}, /* Greek question mark */ + { + 0x0387, 0x0387, 1}, /* Greek ano teleia */ + { + 0x055a, 0x055f, 1}, /* Armenian punctuation */ + { + 0x0589, 0x0589, 1}, /* Armenian full stop */ + { + 0x0700, 0x070d, 1}, /* Syriac punctuation */ + { + 0x104a, 0x104f, 1}, /* Myanmar punctuation */ + { + 0x10fb, 0x10fb, 1}, /* Georgian punctuation */ + { + 0x1361, 0x1368, 1}, /* Ethiopic punctuation */ + { + 0x166d, 0x166e, 1}, /* Canadian Syl. punctuation */ + { + 0x17d4, 0x17dc, 1}, /* Khmer punctuation */ + { + 0x1800, 0x180a, 1}, /* Mongolian punctuation */ + { + 0x2000, 0x200a, 0}, /* Various spaces */ + { + 0x2070, 0x207f, 2}, /* superscript */ + { + 0x2080, 0x208f, 2}, /* subscript */ + { + 0x200b, 0x27ff, 1}, /* punctuation and symbols */ + { + 0x3000, 0x3000, 0}, /* ideographic space */ + { + 0x3001, 0x3020, 1}, /* ideographic punctuation */ + { + 0x303f, 0x309f, 3}, /* Hiragana */ + { + 0x30a0, 0x30ff, 3}, /* Katakana */ + { + 0x3300, 0x9fff, 3}, /* CJK Ideographs */ + { + 0xac00, 0xd7a3, 3}, /* Hangul Syllables */ + { + 0xf900, 0xfaff, 3}, /* CJK Ideographs */ + { + 0xfe30, 0xfe6b, 1}, /* punctuation forms */ + { + 0xff00, 0xff0f, 1}, /* half/fullwidth ASCII */ + { + 0xff1a, 0xff20, 1}, /* half/fullwidth ASCII */ + { + 0xff3b, 0xff40, 1}, /* half/fullwidth ASCII */ + { + 0xff5b, 0xff64, 1}, /* half/fullwidth ASCII */ + { + 0xfff0, 0xffff, 0}, /* half/fullwidth ASCII */ + { + 0, 0, 0} + }; + + uc &= (CSET_MASK | CHAR_MASK); + + switch (uc & CSET_MASK) { + case ATTR_LINEDRW: + uc = unitab_xterm[uc & 0xFF]; + break; + case ATTR_ASCII: + uc = unitab_line[uc & 0xFF]; + break; + } + switch (uc & CSET_MASK) { + case ATTR_ACP: + uc = unitab_font[uc & 0xFF]; + break; + case ATTR_OEMCP: + uc = unitab_oemcp[uc & 0xFF]; + break; + } + + if (uc < 0x80) + return wordness[uc]; + + for (wptr = ucs_words; wptr->start; wptr++) { + if (uc >= wptr->start && uc <= wptr->end) + return wptr->ctype; + } + + return 2; } /* @@ -2366,7 +2908,7 @@ static pos sel_spread_half(pos p, int dir) * In this mode, every character is a separate unit, except * for runs of spaces at the end of a non-wrapping line. */ - if (!(ldata[cols] & ATTR_WRAPPED)) { + if (!(ldata[cols] & LATTR_WRAPPED)) { unsigned long *q = ldata + cols; while (q > ldata && (q[-1] & CHAR_MASK) == 0x20) q--; @@ -2381,15 +2923,13 @@ static pos sel_spread_half(pos p, int dir) * In this mode, the units are maximal runs of characters * whose `wordness' has the same value. */ - wvalue = wordness[ldata[p.x] & CHAR_MASK]; + wvalue = wordtype(ldata[p.x]); if (dir == +1) { - while (p.x < cols - && wordness[ldata[p.x + 1] & CHAR_MASK] == - wvalue) p.x++; + while (p.x < cols && wordtype(ldata[p.x + 1]) == wvalue) + p.x++; } else { - while (p.x > 0 - && wordness[ldata[p.x - 1] & CHAR_MASK] == - wvalue) p.x--; + while (p.x > 0 && wordtype(ldata[p.x - 1]) == wvalue) + p.x--; } break; case SM_LINE: @@ -2534,51 +3074,49 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y, * We've completed a selection. We now transfer the * data to the clipboard. */ - clipme(selstart, selend, selspace); + clipme(selstart, selend); selstate = SELECTED; } else selstate = NO_SELECTION; } else if (b == MBT_PASTE && (a == MA_CLICK || a == MA_2CLK || a == MA_3CLK)) { - char *data; + wchar_t *data; int len; - get_clip((void **) &data, &len); + get_clip(&data, &len); if (data) { - char *p, *q; + wchar_t *p, *q; if (paste_buffer) sfree(paste_buffer); paste_pos = paste_hold = paste_len = 0; - paste_buffer = smalloc(len); + paste_buffer = smalloc(len * sizeof(wchar_t)); p = q = data; while (p < data + len) { while (p < data + len && - !(p <= data + len - sizeof(sel_nl) && + !(p <= data + len - sel_nl_sz && !memcmp(p, sel_nl, sizeof(sel_nl)))) p++; { int i; - unsigned char c; for (i = 0; i < p - q; i++) { - c = xlat_kbd2tty(q[i]); - paste_buffer[paste_len++] = c; + paste_buffer[paste_len++] = q[i]; } } - if (p <= data + len - sizeof(sel_nl) && + if (p <= data + len - sel_nl_sz && !memcmp(p, sel_nl, sizeof(sel_nl))) { paste_buffer[paste_len++] = '\r'; - p += sizeof(sel_nl); + p += sel_nl_sz; } q = p; } /* Assume a small paste will be OK in one go. */ if (paste_len < 256) { - ldisc_send(paste_buffer, paste_len); + luni_send(paste_buffer, paste_len); if (paste_buffer) sfree(paste_buffer); paste_buffer = 0; @@ -2623,7 +3161,7 @@ void term_paste() if (paste_buffer[paste_pos + n++] == '\r') break; } - ldisc_send(paste_buffer + paste_pos, n); + luni_send(paste_buffer + paste_pos, n); paste_pos += n; if (paste_pos < paste_len) { diff --git a/unicode.c b/unicode.c new file mode 100644 index 00000000..06840456 --- /dev/null +++ b/unicode.c @@ -0,0 +1,982 @@ +#include + +#include +#include +#include + +#include +#include "putty.h" + +void init_ucs_tables(void); +void lpage_send(int codepage, char *buf, int len); +void luni_send(wchar_t * widebuf, int len); + +static void get_unitab(int codepage, wchar_t * unitab, int ftype); + +/* Character conversion arrays; they are usually taken from windows, + * the xterm one has the four scanlines that have no unicode 2.0 + * equlivents mapped into the private area. + */ +static char **uni_tbl; + +static WCHAR unitab_xterm_std[32] = { + 0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, + 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, + 0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, + 0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020 +}; + +extern struct cp_list_item { + char *name; + int codepage; + int cp_size; + wchar_t *cp_table; +} cp_list[]; + +static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr); + +void init_ucs_tables(void) +{ + int i, j; + int used_dtf = 0; + char tbuf[256]; + for (i = 0; i < 256; i++) + tbuf[i] = i; + + /* Decide on the Line and Font codepages */ + line_codepage = decode_codepage(cfg.line_codepage); + + if (cfg.vtmode == VT_OEMONLY) { + font_codepage = 437; + dbcs_screenfont = 0; + if (line_codepage <= 0) + line_codepage = GetACP(); + } else if (line_codepage <= 0) + line_codepage = font_codepage; + utf = (line_codepage == CP_UTF8); + + /* Collect screen font ucs table */ + if (dbcs_screenfont) { + get_unitab(font_codepage, unitab_font, 2); + for (i = 128; i < 256; i++) + unitab_font[i] = (WCHAR) (ATTR_ACP + i); + } else { + get_unitab(font_codepage, unitab_font, 1); + + /* CP437 fonts are often broken ... */ + if (font_codepage == 437) + unitab_font[0] = unitab_font[255] = 0xFFFF; + } + if (cfg.vtmode == VT_XWINDOWS) + memcpy(unitab_font + 1, unitab_xterm_std, + sizeof(unitab_xterm_std)); + + /* Collect OEMCP ucs table */ + get_unitab(CP_OEMCP, unitab_oemcp, 1); + + /* Collect line set ucs table */ + if (line_codepage == font_codepage && + (dbcs_screenfont || cfg.vtmode == VT_POORMAN)) { + + /* For DBCS and POOR fonts force direct to font */ + used_dtf = 1; + for (i = 0; i < 32; i++) + unitab_line[i] = (WCHAR) i; + for (i = 32; i < 256; i++) + unitab_line[i] = (WCHAR) (ATTR_ACP + i); + unitab_line[127] = (WCHAR) 127; + } else { + get_unitab(line_codepage, unitab_line, 0); + } + +#if 0 + debug( + ("Line cp%d, Font cp%d%s\n", line_codepage, font_codepage, + dbcs_screenfont ? " DBCS" : "")); + + for (i = 0; i < 256; i += 16) { + for (j = 0; j < 16; j++) { + debug(("%04x%s", unitab_line[i + j], j == 15 ? "" : ",")); + } + debug(("\n")); + } +#endif + + /* VT100 graphics - NB: Broken for non-ascii CP's */ + memcpy(unitab_xterm, unitab_line, sizeof(unitab_xterm)); + memcpy(unitab_xterm + '`', unitab_xterm_std, sizeof(unitab_xterm_std)); + unitab_xterm['_'] = ' '; + + /* Generate UCS ->line page table. */ + if (uni_tbl) { + for (i = 0; i < 256; i++) + if (uni_tbl[i]) + sfree(uni_tbl[i]); + sfree(uni_tbl); + uni_tbl = 0; + } + if (!used_dtf) { + for (i = 0; i < 256; i++) { + if (DIRECT_CHAR(unitab_line[i])) + continue; + if (DIRECT_FONT(unitab_line[i])) + continue; + if (!uni_tbl) { + uni_tbl = smalloc(256 * sizeof(char *)); + memset(uni_tbl, 0, 256 * sizeof(char *)); + } + j = ((unitab_line[i] >> 8) & 0xFF); + if (!uni_tbl[j]) { + uni_tbl[j] = smalloc(256 * sizeof(char)); + memset(uni_tbl[j], 0, 256 * sizeof(char)); + } + uni_tbl[j][unitab_line[i] & 0xFF] = i; + } + } + + /* 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; + else + unitab_ctrl[i] = 0xFF; + + /* Generate line->screen direct conversion links. */ + link_font(unitab_line, unitab_font, ATTR_ACP); + link_font(unitab_xterm, unitab_font, ATTR_ACP); + + if (cfg.vtmode == VT_OEMANSI || cfg.vtmode == VT_XWINDOWS) { + link_font(unitab_line, unitab_oemcp, ATTR_OEMCP); + link_font(unitab_xterm, unitab_oemcp, ATTR_OEMCP); + } + + /* Last chance, if !unicode then try poorman links. */ + if (cfg.vtmode != VT_UNICODE) { + static char poorman_latin1[] = + " !cL.Y|S\"Ca<--R~o+23'u|.,1o>///?AAAAAAACEEEEIIIIDNOOOOOxOUUUUYPBaaaaaaaceeeeiiiionooooo/ouuuuypy"; + static char poorman_vt100[] = "*#****o~**+++++-----++++|****L."; + + for (i = 160; i < 256; i++) + if (!DIRECT_FONT(unitab_line[i]) && + unitab_line[i] >= 160 && unitab_line[i] < 256) + unitab_line[i] = (WCHAR) (ATTR_ACP + + poorman_latin1[unitab_line[i] - + 160]); + for (i = 96; i < 127; i++) + if (!DIRECT_FONT(unitab_xterm[i])) + unitab_xterm[i] = + (WCHAR) (ATTR_ACP + poorman_vt100[i - 96]); + } +} + +static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr) +{ + int i, j, k; + for (k = 0; k < 256; k++) { + i = ((k + 32) & 0xFF); + if (DIRECT_FONT(line_tbl[i])) + continue; + for (j = 0; j < 256; j++) { + if (line_tbl[i] == font_tbl[j]) { + line_tbl[i] = (WCHAR) (attr + j); + break; + } + } + } +} + +void lpage_send(int codepage, char *buf, int len) +{ + static wchar_t *widebuffer = 0; + static int widesize = 0; + int wclen; + + if (codepage < 0) { + ldisc_send(buf, len); + return; + } + + if (len > widesize) { + sfree(widebuffer); + widebuffer = smalloc(len * 2 * sizeof(wchar_t)); + widesize = len * 2; + } + + wclen = + MultiByteToWideChar(codepage, 0, buf, len, widebuffer, widesize); + luni_send(widebuffer, wclen); +} + +void luni_send(wchar_t * widebuf, int len) +{ + static char *linebuffer = 0; + static int linesize = 0; + int ratio = (utf) ? 3 : 1; + int i; + char *p; + + if (len * ratio > linesize) { + sfree(linebuffer); + linebuffer = smalloc(len * ratio * 2 * sizeof(wchar_t)); + linesize = len * ratio * 2; + } + + if (utf) { + /* UTF is a simple algorithm */ + for (p = linebuffer, i = 0; i < len; i++) { + wchar_t ch = widebuf[i]; + if (ch < 0x80) { + *p++ = (char) (ch); + } else if (ch < 0x800) { + *p++ = (0xC0 | (ch >> 6)); + *p++ = (0x80 | (ch & 0x3F)); + } else { + *p++ = (0xE0 | (ch >> 12)); + *p++ = (0x80 | ((ch >> 6) & 0x3F)); + *p++ = (0x80 | (ch & 0x3F)); + } + } + } else if (!uni_tbl) { + int rv; + rv = WideCharToMultiByte(line_codepage, 0, widebuf, len, + linebuffer, linesize, NULL, NULL); + if (rv >= 0) + p = linebuffer + rv; + else + p = linebuffer; + } else { + /* Others are a lookup in an array */ + for (p = linebuffer, i = 0; i < len; i++) { + wchar_t ch = widebuf[i]; + int by; + char *p1; + if (uni_tbl && (p1 = uni_tbl[(ch >> 8) & 0xFF]) + && (by = p1[ch & 0xFF])) + *p++ = by; + else if (ch < 0x80) + *p++ = (char) ch; +#if 1 + else + *p++ = '.'; +#endif + } + } + if (p > linebuffer) + ldisc_send(linebuffer, p - linebuffer); +} + +int check_compose(int first, int second) +{ + + static struct { + char first, second; + wchar_t composed; + } composetbl[] = { + { + 0x2b, 0x2b, 0x0023}, { + 0x41, 0x41, 0x0040}, { + 0x28, 0x28, 0x005b}, { + 0x2f, 0x2f, 0x005c}, { + 0x29, 0x29, 0x005d}, { + 0x28, 0x2d, 0x007b}, { + 0x2d, 0x29, 0x007d}, { + 0x2f, 0x5e, 0x007c}, { + 0x21, 0x21, 0x00a1}, { + 0x43, 0x2f, 0x00a2}, { + 0x43, 0x7c, 0x00a2}, { + 0x4c, 0x2d, 0x00a3}, { + 0x4c, 0x3d, 0x00a3}, { + 0x58, 0x4f, 0x00a4}, { + 0x58, 0x30, 0x00a4}, { + 0x59, 0x2d, 0x00a5}, { + 0x59, 0x3d, 0x00a5}, { + 0x7c, 0x7c, 0x00a6}, { + 0x53, 0x4f, 0x00a7}, { + 0x53, 0x21, 0x00a7}, { + 0x53, 0x30, 0x00a7}, { + 0x22, 0x22, 0x00a8}, { + 0x43, 0x4f, 0x00a9}, { + 0x43, 0x30, 0x00a9}, { + 0x41, 0x5f, 0x00aa}, { + 0x3c, 0x3c, 0x00ab}, { + 0x2c, 0x2d, 0x00ac}, { + 0x2d, 0x2d, 0x00ad}, { + 0x52, 0x4f, 0x00ae}, { + 0x2d, 0x5e, 0x00af}, { + 0x30, 0x5e, 0x00b0}, { + 0x2b, 0x2d, 0x00b1}, { + 0x32, 0x5e, 0x00b2}, { + 0x33, 0x5e, 0x00b3}, { + 0x27, 0x27, 0x00b4}, { + 0x2f, 0x55, 0x00b5}, { + 0x50, 0x21, 0x00b6}, { + 0x2e, 0x5e, 0x00b7}, { + 0x2c, 0x2c, 0x00b8}, { + 0x31, 0x5e, 0x00b9}, { + 0x4f, 0x5f, 0x00ba}, { + 0x3e, 0x3e, 0x00bb}, { + 0x31, 0x34, 0x00bc}, { + 0x31, 0x32, 0x00bd}, { + 0x33, 0x34, 0x00be}, { + 0x3f, 0x3f, 0x00bf}, { + 0x60, 0x41, 0x00c0}, { + 0x27, 0x41, 0x00c1}, { + 0x5e, 0x41, 0x00c2}, { + 0x7e, 0x41, 0x00c3}, { + 0x22, 0x41, 0x00c4}, { + 0x2a, 0x41, 0x00c5}, { + 0x41, 0x45, 0x00c6}, { + 0x2c, 0x43, 0x00c7}, { + 0x60, 0x45, 0x00c8}, { + 0x27, 0x45, 0x00c9}, { + 0x5e, 0x45, 0x00ca}, { + 0x22, 0x45, 0x00cb}, { + 0x60, 0x49, 0x00cc}, { + 0x27, 0x49, 0x00cd}, { + 0x5e, 0x49, 0x00ce}, { + 0x22, 0x49, 0x00cf}, { + 0x2d, 0x44, 0x00d0}, { + 0x7e, 0x4e, 0x00d1}, { + 0x60, 0x4f, 0x00d2}, { + 0x27, 0x4f, 0x00d3}, { + 0x5e, 0x4f, 0x00d4}, { + 0x7e, 0x4f, 0x00d5}, { + 0x22, 0x4f, 0x00d6}, { + 0x58, 0x58, 0x00d7}, { + 0x2f, 0x4f, 0x00d8}, { + 0x60, 0x55, 0x00d9}, { + 0x27, 0x55, 0x00da}, { + 0x5e, 0x55, 0x00db}, { + 0x22, 0x55, 0x00dc}, { + 0x27, 0x59, 0x00dd}, { + 0x48, 0x54, 0x00de}, { + 0x73, 0x73, 0x00df}, { + 0x60, 0x61, 0x00e0}, { + 0x27, 0x61, 0x00e1}, { + 0x5e, 0x61, 0x00e2}, { + 0x7e, 0x61, 0x00e3}, { + 0x22, 0x61, 0x00e4}, { + 0x2a, 0x61, 0x00e5}, { + 0x61, 0x65, 0x00e6}, { + 0x2c, 0x63, 0x00e7}, { + 0x60, 0x65, 0x00e8}, { + 0x27, 0x65, 0x00e9}, { + 0x5e, 0x65, 0x00ea}, { + 0x22, 0x65, 0x00eb}, { + 0x60, 0x69, 0x00ec}, { + 0x27, 0x69, 0x00ed}, { + 0x5e, 0x69, 0x00ee}, { + 0x22, 0x69, 0x00ef}, { + 0x2d, 0x64, 0x00f0}, { + 0x7e, 0x6e, 0x00f1}, { + 0x60, 0x6f, 0x00f2}, { + 0x27, 0x6f, 0x00f3}, { + 0x5e, 0x6f, 0x00f4}, { + 0x7e, 0x6f, 0x00f5}, { + 0x22, 0x6f, 0x00f6}, { + 0x3a, 0x2d, 0x00f7}, { + 0x6f, 0x2f, 0x00f8}, { + 0x60, 0x75, 0x00f9}, { + 0x27, 0x75, 0x00fa}, { + 0x5e, 0x75, 0x00fb}, { + 0x22, 0x75, 0x00fc}, { + 0x27, 0x79, 0x00fd}, { + 0x68, 0x74, 0x00fe}, { + 0x22, 0x79, 0x00ff}, + /* Unicode extras. */ + { + 0x6f, 0x65, 0x0153}, { + 0x4f, 0x45, 0x0152}, + /* Compose pairs from UCS */ + { + 0x41, 0x2D, 0x0100}, { + 0x61, 0x2D, 0x0101}, { + 0x43, 0x27, 0x0106}, { + 0x63, 0x27, 0x0107}, { + 0x43, 0x5E, 0x0108}, { + 0x63, 0x5E, 0x0109}, { + 0x45, 0x2D, 0x0112}, { + 0x65, 0x2D, 0x0113}, { + 0x47, 0x5E, 0x011C}, { + 0x67, 0x5E, 0x011D}, { + 0x47, 0x2C, 0x0122}, { + 0x67, 0x2C, 0x0123}, { + 0x48, 0x5E, 0x0124}, { + 0x68, 0x5E, 0x0125}, { + 0x49, 0x7E, 0x0128}, { + 0x69, 0x7E, 0x0129}, { + 0x49, 0x2D, 0x012A}, { + 0x69, 0x2D, 0x012B}, { + 0x4A, 0x5E, 0x0134}, { + 0x6A, 0x5E, 0x0135}, { + 0x4B, 0x2C, 0x0136}, { + 0x6B, 0x2C, 0x0137}, { + 0x4C, 0x27, 0x0139}, { + 0x6C, 0x27, 0x013A}, { + 0x4C, 0x2C, 0x013B}, { + 0x6C, 0x2C, 0x013C}, { + 0x4E, 0x27, 0x0143}, { + 0x6E, 0x27, 0x0144}, { + 0x4E, 0x2C, 0x0145}, { + 0x6E, 0x2C, 0x0146}, { + 0x4F, 0x2D, 0x014C}, { + 0x6F, 0x2D, 0x014D}, { + 0x52, 0x27, 0x0154}, { + 0x72, 0x27, 0x0155}, { + 0x52, 0x2C, 0x0156}, { + 0x72, 0x2C, 0x0157}, { + 0x53, 0x27, 0x015A}, { + 0x73, 0x27, 0x015B}, { + 0x53, 0x5E, 0x015C}, { + 0x73, 0x5E, 0x015D}, { + 0x53, 0x2C, 0x015E}, { + 0x73, 0x2C, 0x015F}, { + 0x54, 0x2C, 0x0162}, { + 0x74, 0x2C, 0x0163}, { + 0x55, 0x7E, 0x0168}, { + 0x75, 0x7E, 0x0169}, { + 0x55, 0x2D, 0x016A}, { + 0x75, 0x2D, 0x016B}, { + 0x55, 0x2A, 0x016E}, { + 0x75, 0x2A, 0x016F}, { + 0x57, 0x5E, 0x0174}, { + 0x77, 0x5E, 0x0175}, { + 0x59, 0x5E, 0x0176}, { + 0x79, 0x5E, 0x0177}, { + 0x59, 0x22, 0x0178}, { + 0x5A, 0x27, 0x0179}, { + 0x7A, 0x27, 0x017A}, { + 0x47, 0x27, 0x01F4}, { + 0x67, 0x27, 0x01F5}, { + 0x4E, 0x60, 0x01F8}, { + 0x6E, 0x60, 0x01F9}, { + 0x45, 0x2C, 0x0228}, { + 0x65, 0x2C, 0x0229}, { + 0x59, 0x2D, 0x0232}, { + 0x79, 0x2D, 0x0233}, { + 0x44, 0x2C, 0x1E10}, { + 0x64, 0x2C, 0x1E11}, { + 0x47, 0x2D, 0x1E20}, { + 0x67, 0x2D, 0x1E21}, { + 0x48, 0x22, 0x1E26}, { + 0x68, 0x22, 0x1E27}, { + 0x48, 0x2C, 0x1E28}, { + 0x68, 0x2C, 0x1E29}, { + 0x4B, 0x27, 0x1E30}, { + 0x6B, 0x27, 0x1E31}, { + 0x4D, 0x27, 0x1E3E}, { + 0x6D, 0x27, 0x1E3F}, { + 0x50, 0x27, 0x1E54}, { + 0x70, 0x27, 0x1E55}, { + 0x56, 0x7E, 0x1E7C}, { + 0x76, 0x7E, 0x1E7D}, { + 0x57, 0x60, 0x1E80}, { + 0x77, 0x60, 0x1E81}, { + 0x57, 0x27, 0x1E82}, { + 0x77, 0x27, 0x1E83}, { + 0x57, 0x22, 0x1E84}, { + 0x77, 0x22, 0x1E85}, { + 0x58, 0x22, 0x1E8C}, { + 0x78, 0x22, 0x1E8D}, { + 0x5A, 0x5E, 0x1E90}, { + 0x7A, 0x5E, 0x1E91}, { + 0x74, 0x22, 0x1E97}, { + 0x77, 0x2A, 0x1E98}, { + 0x79, 0x2A, 0x1E99}, { + 0x45, 0x7E, 0x1EBC}, { + 0x65, 0x7E, 0x1EBD}, { + 0x59, 0x60, 0x1EF2}, { + 0x79, 0x60, 0x1EF3}, { + 0x59, 0x7E, 0x1EF8}, { + 0x79, 0x7E, 0x1EF9}, + /* Compatible/possibles from UCS */ + { + 0x49, 0x4A, 0x0132}, { + 0x69, 0x6A, 0x0133}, { + 0x4C, 0x4A, 0x01C7}, { + 0x4C, 0x6A, 0x01C8}, { + 0x6C, 0x6A, 0x01C9}, { + 0x4E, 0x4A, 0x01CA}, { + 0x4E, 0x6A, 0x01CB}, { + 0x6E, 0x6A, 0x01CC}, { + 0x44, 0x5A, 0x01F1}, { + 0x44, 0x7A, 0x01F2}, { + 0x64, 0x7A, 0x01F3}, { + 0x2E, 0x2E, 0x2025}, { + 0x21, 0x21, 0x203C}, { + 0x3F, 0x21, 0x2048}, { + 0x21, 0x3F, 0x2049}, { + 0x52, 0x73, 0x20A8}, { + 0x4E, 0x6F, 0x2116}, { + 0x53, 0x4D, 0x2120}, { + 0x54, 0x4D, 0x2122}, { + 0x49, 0x49, 0x2161}, { + 0x49, 0x56, 0x2163}, { + 0x56, 0x49, 0x2165}, { + 0x49, 0x58, 0x2168}, { + 0x58, 0x49, 0x216A}, { + 0x69, 0x69, 0x2171}, { + 0x69, 0x76, 0x2173}, { + 0x76, 0x69, 0x2175}, { + 0x69, 0x78, 0x2178}, { + 0x78, 0x69, 0x217A}, { + 0x31, 0x30, 0x2469}, { + 0x31, 0x31, 0x246A}, { + 0x31, 0x32, 0x246B}, { + 0x31, 0x33, 0x246C}, { + 0x31, 0x34, 0x246D}, { + 0x31, 0x35, 0x246E}, { + 0x31, 0x36, 0x246F}, { + 0x31, 0x37, 0x2470}, { + 0x31, 0x38, 0x2471}, { + 0x31, 0x39, 0x2472}, { + 0x32, 0x30, 0x2473}, { + 0x31, 0x2E, 0x2488}, { + 0x32, 0x2E, 0x2489}, { + 0x33, 0x2E, 0x248A}, { + 0x34, 0x2E, 0x248B}, { + 0x35, 0x2E, 0x248C}, { + 0x36, 0x2E, 0x248D}, { + 0x37, 0x2E, 0x248E}, { + 0x38, 0x2E, 0x248F}, { + 0x39, 0x2E, 0x2490}, { + 0x64, 0x61, 0x3372}, { + 0x41, 0x55, 0x3373}, { + 0x6F, 0x56, 0x3375}, { + 0x70, 0x63, 0x3376}, { + 0x70, 0x41, 0x3380}, { + 0x6E, 0x41, 0x3381}, { + 0x6D, 0x41, 0x3383}, { + 0x6B, 0x41, 0x3384}, { + 0x4B, 0x42, 0x3385}, { + 0x4D, 0x42, 0x3386}, { + 0x47, 0x42, 0x3387}, { + 0x70, 0x46, 0x338A}, { + 0x6E, 0x46, 0x338B}, { + 0x6D, 0x67, 0x338E}, { + 0x6B, 0x67, 0x338F}, { + 0x48, 0x7A, 0x3390}, { + 0x66, 0x6D, 0x3399}, { + 0x6E, 0x6D, 0x339A}, { + 0x6D, 0x6D, 0x339C}, { + 0x63, 0x6D, 0x339D}, { + 0x6B, 0x6D, 0x339E}, { + 0x50, 0x61, 0x33A9}, { + 0x70, 0x73, 0x33B0}, { + 0x6E, 0x73, 0x33B1}, { + 0x6D, 0x73, 0x33B3}, { + 0x70, 0x56, 0x33B4}, { + 0x6E, 0x56, 0x33B5}, { + 0x6D, 0x56, 0x33B7}, { + 0x6B, 0x56, 0x33B8}, { + 0x4D, 0x56, 0x33B9}, { + 0x70, 0x57, 0x33BA}, { + 0x6E, 0x57, 0x33BB}, { + 0x6D, 0x57, 0x33BD}, { + 0x6B, 0x57, 0x33BE}, { + 0x4D, 0x57, 0x33BF}, { + 0x42, 0x71, 0x33C3}, { + 0x63, 0x63, 0x33C4}, { + 0x63, 0x64, 0x33C5}, { + 0x64, 0x42, 0x33C8}, { + 0x47, 0x79, 0x33C9}, { + 0x68, 0x61, 0x33CA}, { + 0x48, 0x50, 0x33CB}, { + 0x69, 0x6E, 0x33CC}, { + 0x4B, 0x4B, 0x33CD}, { + 0x4B, 0x4D, 0x33CE}, { + 0x6B, 0x74, 0x33CF}, { + 0x6C, 0x6D, 0x33D0}, { + 0x6C, 0x6E, 0x33D1}, { + 0x6C, 0x78, 0x33D3}, { + 0x6D, 0x62, 0x33D4}, { + 0x50, 0x48, 0x33D7}, { + 0x50, 0x52, 0x33DA}, { + 0x73, 0x72, 0x33DB}, { + 0x53, 0x76, 0x33DC}, { + 0x57, 0x62, 0x33DD}, { + 0x66, 0x66, 0xFB00}, { + 0x66, 0x69, 0xFB01}, { + 0x66, 0x6C, 0xFB02}, { + 0x73, 0x74, 0xFB06}, { + 0, 0, 0} + }, *c; + + static int recurse = 0; + int nc = -1; + + for (c = composetbl; c->first; c++) { + if (c->first == first && c->second == second) + return c->composed; + } + + if (recurse == 0) { + recurse = 1; + nc = check_compose(second, first); + if (nc == -1) + nc = check_compose(toupper(first), toupper(second)); + if (nc == -1) + nc = check_compose(toupper(second), toupper(first)); + recurse = 0; + } + return nc; +} + +int decode_codepage(char *cp_name) +{ + char *s, *d; + struct cp_list_item *cpi; + int codepage = -1; + char ch; + CPINFO cpinfo; + + if (cp_name && *cp_name) + for (cpi = cp_list; cpi->name; cpi++) { + s = cp_name; + d = cpi->name; + for (;;) { + while (*s && !isalnum(*s) && *s != ':') + s++; + while (*d && !isalnum(*d) && *d != ':') + d++; + if (*s == 0) { + codepage = cpi->codepage; + if (codepage == CP_UTF8) + goto break_break; + if (codepage == 0) { + codepage = 65536 + (cpi - cp_list); + goto break_break; + } + + if (GetCPInfo(codepage, &cpinfo) != 0) + goto break_break; + } + if (islower(*s)) + ch = toupper(*s++); + else + ch = *s++; + if (ch != *d++) + break; + } + } + + if (cp_name && *cp_name) { + d = cp_name; + if (strnicmp(d, "cp", 2) == 0) + d += 2; + if (strnicmp(d, "ibm", 3) == 0) + d += 3; + for (s = d; *s >= '0' && *s <= '9'; s++); + if (*s == 0 && s != d) + codepage = atoi(d); /* CP999 or IBM999 */ + + if (codepage == CP_ACP) + codepage = GetACP(); + if (codepage == CP_OEMCP) + codepage = GetOEMCP(); + if (codepage > 65535) + codepage = -2; + } + + break_break:; + if (codepage != -1) { + if (codepage != CP_UTF8 && codepage < 65536) { + if (GetCPInfo(codepage, &cpinfo) == 0) { + codepage = -2; + } else if (cpinfo.MaxCharSize > 1) + codepage = -3; + } + } + if (codepage == -1 && *cp_name) + codepage = -2; + return codepage; +} + +char *cp_name(int codepage) +{ + struct cp_list_item *cpi, *cpno; + static char buf[32]; + if (codepage > 0 && codepage < 65536) + sprintf(buf, "CP%03d", codepage); + else + *buf = 0; + + if (codepage >= 65536) { + cpno = 0; + for (cpi = cp_list; cpi->name; cpi++) + if (cpi == cp_list + (codepage - 65536)) { + cpno = cpi; + break; + } + if (cpno) + for (cpi = cp_list; cpi->name; cpi++) { + if (cpno->cp_table == cpi->cp_table) + return cpi->name; + } + } else { + for (cpi = cp_list; cpi->name; cpi++) { + if (codepage == cpi->codepage) + return cpi->name; + } + } + return buf; +} + +static void get_unitab(int codepage, wchar_t * unitab, int ftype) +{ + char tbuf[4]; + int i, max = 256, flg = MB_ERR_INVALID_CHARS; + + if (ftype) + flg |= MB_USEGLYPHCHARS; + if (ftype == 2) + max = 128; + + if (codepage == CP_UTF8) + codepage = 28591; + else if (codepage == CP_ACP) + codepage = GetACP(); + else if (codepage == CP_OEMCP) + codepage = GetOEMCP(); + + if (codepage > 0 && codepage < 65536) { + for (i = 0; i < max; i++) { + tbuf[0] = i; + + if (MultiByteToWideChar(codepage, flg, tbuf, 1, unitab + i, 1) + != 1) + unitab[i] = 0xFFFD; + } + } else { + int j = 256 - cp_list[codepage & 0xFFFF].cp_size; + for (i = 0; i < max; i++) + unitab[i] = i; + for (i = j; i < max; i++) + unitab[i] = cp_list[codepage & 0xFFFF].cp_table[i - j]; + } +} + +/* + * From here down is the codepage data, if you want to add your own line + * codepage do it here. + * + * If the codepage is non-zero it's a window codepage, zero means use a + * local codepage. The name is always converted to the first of any + * duplicate definitions. + */ +extern wchar_t iso_8859_10[]; +extern wchar_t iso_8859_11[]; +extern wchar_t iso_8859_12[]; +extern wchar_t iso_8859_14[]; +extern wchar_t iso_8859_15[]; +extern wchar_t roman8[]; +extern wchar_t koi8_u[]; +extern wchar_t vscii[]; +extern wchar_t dec_mcs[]; + +static struct cp_list_item cp_list[] = { + {"UTF-8", CP_UTF8}, + + {"ISO-8859-1:1987", 28591}, + {"ISO-8859-2:1987", 28592}, + {"ISO-8859-3:1988", 28593}, + {"ISO-8859-4:1988", 28594}, + {"ISO-8859-5:1988", 28595}, + {"ISO-8859-6:1987", 28596}, + {"ISO-8859-7:1987", 28597}, + {"ISO-8859-8:1988", 28598}, + {"ISO-8859-9:1989", 28599}, + {"ISO-8859-10:1993", 0, 96, iso_8859_10}, + {"ISO-8859-11", 0, 96, iso_8859_11}, + {"ISO-8859-12", 0, 96, iso_8859_12}, + {"ISO-8859-14", 0, 96, iso_8859_14}, + {"ISO-8859-15:1998", 0, 96, iso_8859_15}, + + {"KOI8-U", 0, 128, koi8_u}, + {"KOI8-R", 20866}, + {"HP-ROMAN8", 0, 96, roman8}, + {"VSCII", 0, 256, vscii}, + {"DEC-MCS", 0, 96, dec_mcs}, + +/* All below here are aliases */ + {"ROMAN8", 0, 96, roman8}, + {"R8", 0, 96, roman8}, + + /* Note this is Latin ->> */ + {"LATIN0", 0, 96, iso_8859_15}, + {"L0", 0, 96, iso_8859_15}, + + {"CP819", 28591}, + {"CP878", 20866}, + {"L1", 28591}, + {"L2", 28592}, + {"L3", 28593}, + {"L4", 28594}, + {"L5", 28599}, + {"LATIN1", 28591}, + {"LATIN2", 28592}, + {"LATIN3", 28593}, + {"LATIN4", 28594}, + {"LATIN5", 28599}, + {0, 0} +}; + +static wchar_t iso_8859_10[] = { + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2014, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138 +}; + +static wchar_t iso_8859_11[] = { + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD +}; + +static wchar_t iso_8859_12[] = { + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019 +}; + +static wchar_t iso_8859_14[] = { + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF +}; + +static wchar_t iso_8859_15[] = { + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20ac, 0x00a5, 0x0160, 0x00a7, + 0x0161, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x017d, 0x00b5, 0x00b6, 0x00b7, + 0x017e, 0x00b9, 0x00ba, 0x00bb, 0x0152, 0x0153, 0x0178, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff +}; + +static wchar_t roman8[] = { + 0x00A0, 0x00C0, 0x00C2, 0x00C8, 0x00CA, 0x00CB, 0x00CE, 0x00CF, + 0x00B4, 0x02CB, 0x02C6, 0x00A8, 0x02DC, 0x00D9, 0x00DB, 0x20A4, + 0x00AF, 0x00DD, 0x00FD, 0x00B0, 0x00C7, 0x00E7, 0x00D1, 0x00F1, + 0x00A1, 0x00BF, 0x00A4, 0x00A3, 0x00A5, 0x00A7, 0x0192, 0x00A2, + 0x00E2, 0x00EA, 0x00F4, 0x00FB, 0x00E1, 0x00E9, 0x00F3, 0x00FA, + 0x00E0, 0x00E8, 0x00F2, 0x00F9, 0x00E4, 0x00EB, 0x00F6, 0x00FC, + 0x00C5, 0x00EE, 0x00D8, 0x00C6, 0x00E5, 0x00ED, 0x00F8, 0x00E6, + 0x00C4, 0x00EC, 0x00D6, 0x00DC, 0x00C9, 0x00EF, 0x00DF, 0x00D4, + 0x00C1, 0x00C3, 0x00E3, 0x00D0, 0x00F0, 0x00CD, 0x00CC, 0x00D3, + 0x00D2, 0x00D5, 0x00F5, 0x0160, 0x0161, 0x00DA, 0x0178, 0x00FF, + 0x00DE, 0x00FE, 0x00B7, 0x00B5, 0x00B6, 0x00BE, 0x2014, 0x00BC, + 0x00BD, 0x00AA, 0x00BA, 0x00AB, 0x25A0, 0x00BB, 0x00B1, 0xFFFD +}; + +static wchar_t koi8_u[] = { + 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2022, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A +}; + +static wchar_t vscii[] = { + 0x0000, 0x0001, 0x1EB2, 0x0003, 0x0004, 0x1EB4, 0x1EAA, 0x0007, + 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, + 0x0010, 0x0011, 0x0012, 0x0013, 0x1EF6, 0x0015, 0x0016, 0x0017, + 0x0018, 0x1EF8, 0x001a, 0x001b, 0x001c, 0x001d, 0x1EF4, 0x001f, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007f, + 0x1EA0, 0x1EAE, 0x1EB0, 0x1EB6, 0x1EA4, 0x1EA6, 0x1EA8, 0x1EAC, + 0x1EBC, 0x1EB8, 0x1EBE, 0x1EC0, 0x1EC2, 0x1EC4, 0x1EC6, 0x1ED0, + 0x1ED2, 0x1ED4, 0x1ED6, 0x1ED8, 0x1EE2, 0x1EDA, 0x1EDC, 0x1EDE, + 0x1ECA, 0x1ECE, 0x1ECC, 0x1EC8, 0x1EE6, 0x0168, 0x1EE4, 0x1EF2, + 0x00D5, 0x1EAF, 0x1EB1, 0x1EB7, 0x1EA5, 0x1EA7, 0x1EA8, 0x1EAD, + 0x1EBD, 0x1EB9, 0x1EBF, 0x1EC1, 0x1EC3, 0x1EC5, 0x1EC7, 0x1ED1, + 0x1ED3, 0x1ED5, 0x1ED7, 0x1EE0, 0x01A0, 0x1ED9, 0x1EDD, 0x1EDF, + 0x1ECB, 0x1EF0, 0x1EE8, 0x1EEA, 0x1EEC, 0x01A1, 0x1EDB, 0x01AF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x1EA2, 0x0102, 0x1EB3, 0x1EB5, + 0x00C8, 0x00C9, 0x00CA, 0x1EBA, 0x00CC, 0x00CD, 0x0128, 0x1EF3, + 0x0110, 0x1EE9, 0x00D2, 0x00D3, 0x00D4, 0x1EA1, 0x1EF7, 0x1EEB, + 0x1EED, 0x00D9, 0x00DA, 0x1EF9, 0x1EF5, 0x00DD, 0x1EE1, 0x01B0, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x1EA3, 0x0103, 0x1EEF, 0x1EAB, + 0x00E8, 0x00E9, 0x00EA, 0x1EBB, 0x00EC, 0x00ED, 0x0129, 0x1EC9, + 0x0111, 0x1EF1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x1ECF, 0x1ECD, + 0x1EE5, 0x00F9, 0x00FA, 0x0169, 0x1EE7, 0x00FD, 0x1EE3, 0x1EEE +}; + +static wchar_t dec_mcs[] = { + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0xFFFD, 0x00A5, 0xFFFD, 0x00A7, + 0x00A4, 0x00A9, 0x00AA, 0x00AB, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xFFFD, 0x00B5, 0x00B6, 0x00B7, + 0xFFFD, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0xFFFD, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0152, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0178, 0xFFFD, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0153, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FF, 0xFFFD, 0xFFFD +}; diff --git a/wcwidth.c b/wcwidth.c new file mode 100644 index 00000000..8fa3ee27 --- /dev/null +++ b/wcwidth.c @@ -0,0 +1,190 @@ +/* + * This is an implementation of wcwidth() and wcswidth() as defined in + * "The Single UNIX Specification, Version 2, The Open Group, 1997" + * + * + * Markus Kuhn -- 2000-02-08 -- public domain + */ + +#include + +/* These functions define the column width of an ISO 10646 character + * as follows: + * + * - The null character (U+0000) has a column width of 0. + * + * - Other C0/C1 control characters and DEL will lead to a return + * value of -1. + * + * - Non-spacing and enclosing combining characters (general + * category code Mn or Me in the Unicode database) have a + * column width of 0. + * + * - Spacing characters in the East Asian Wide (W) or East Asian + * FullWidth (F) category as defined in Unicode Technical + * Report #11 have a column width of 2. + * + * - All remaining characters (including all printable + * ISO 8859-1 and WGL4 characters, Unicode control characters, + * etc.) have a column width of 1. + * + * This implementation assumes that wchar_t characters are encoded + * in ISO 10646. + */ + +int wcwidth(wchar_t ucs) +{ + /* sorted list of non-overlapping intervals of non-spacing characters */ + static const struct interval { + unsigned short first; + unsigned short last; + } combining[] = { + { + 0x0300, 0x034E}, { + 0x0360, 0x0362}, { + 0x0483, 0x0486}, { + 0x0488, 0x0489}, { + 0x0591, 0x05A1}, { + 0x05A3, 0x05B9}, { + 0x05BB, 0x05BD}, { + 0x05BF, 0x05BF}, { + 0x05C1, 0x05C2}, { + 0x05C4, 0x05C4}, { + 0x064B, 0x0655}, { + 0x0670, 0x0670}, { + 0x06D6, 0x06E4}, { + 0x06E7, 0x06E8}, { + 0x06EA, 0x06ED}, { + 0x0711, 0x0711}, { + 0x0730, 0x074A}, { + 0x07A6, 0x07B0}, { + 0x0901, 0x0902}, { + 0x093C, 0x093C}, { + 0x0941, 0x0948}, { + 0x094D, 0x094D}, { + 0x0951, 0x0954}, { + 0x0962, 0x0963}, { + 0x0981, 0x0981}, { + 0x09BC, 0x09BC}, { + 0x09C1, 0x09C4}, { + 0x09CD, 0x09CD}, { + 0x09E2, 0x09E3}, { + 0x0A02, 0x0A02}, { + 0x0A3C, 0x0A3C}, { + 0x0A41, 0x0A42}, { + 0x0A47, 0x0A48}, { + 0x0A4B, 0x0A4D}, { + 0x0A70, 0x0A71}, { + 0x0A81, 0x0A82}, { + 0x0ABC, 0x0ABC}, { + 0x0AC1, 0x0AC5}, { + 0x0AC7, 0x0AC8}, { + 0x0ACD, 0x0ACD}, { + 0x0B01, 0x0B01}, { + 0x0B3C, 0x0B3C}, { + 0x0B3F, 0x0B3F}, { + 0x0B41, 0x0B43}, { + 0x0B4D, 0x0B4D}, { + 0x0B56, 0x0B56}, { + 0x0B82, 0x0B82}, { + 0x0BC0, 0x0BC0}, { + 0x0BCD, 0x0BCD}, { + 0x0C3E, 0x0C40}, { + 0x0C46, 0x0C48}, { + 0x0C4A, 0x0C4D}, { + 0x0C55, 0x0C56}, { + 0x0CBF, 0x0CBF}, { + 0x0CC6, 0x0CC6}, { + 0x0CCC, 0x0CCD}, { + 0x0D41, 0x0D43}, { + 0x0D4D, 0x0D4D}, { + 0x0DCA, 0x0DCA}, { + 0x0DD2, 0x0DD4}, { + 0x0DD6, 0x0DD6}, { + 0x0E31, 0x0E31}, { + 0x0E34, 0x0E3A}, { + 0x0E47, 0x0E4E}, { + 0x0EB1, 0x0EB1}, { + 0x0EB4, 0x0EB9}, { + 0x0EBB, 0x0EBC}, { + 0x0EC8, 0x0ECD}, { + 0x0F18, 0x0F19}, { + 0x0F35, 0x0F35}, { + 0x0F37, 0x0F37}, { + 0x0F39, 0x0F39}, { + 0x0F71, 0x0F7E}, { + 0x0F80, 0x0F84}, { + 0x0F86, 0x0F87}, { + 0x0F90, 0x0F97}, { + 0x0F99, 0x0FBC}, { + 0x0FC6, 0x0FC6}, { + 0x102D, 0x1030}, { + 0x1032, 0x1032}, { + 0x1036, 0x1037}, { + 0x1039, 0x1039}, { + 0x1058, 0x1059}, { + 0x17B7, 0x17BD}, { + 0x17C6, 0x17C6}, { + 0x17C9, 0x17D3}, { + 0x18A9, 0x18A9}, { + 0x20D0, 0x20E3}, { + 0x302A, 0x302F}, { + 0x3099, 0x309A}, { + 0xFB1E, 0xFB1E}, { + 0xFE20, 0xFE23} + }; + int min = 0; + int max = sizeof(combining) / sizeof(struct interval) - 1; + int mid; + + /* test for 8-bit control characters */ + if (ucs == 0) + return 0; + if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) + return -1; + + /* first quick check for Latin-1 etc. characters */ + if (ucs < combining[0].first) + return 1; + + /* binary search in table of non-spacing characters */ + while (max >= min) { + mid = (min + max) / 2; + if (combining[mid].last < ucs) + min = mid + 1; + else if (combining[mid].first > ucs) + max = mid - 1; + else if (combining[mid].first <= ucs && combining[mid].last >= ucs) + return 0; + } + + /* if we arrive here, ucs is not a combining or C0/C1 control character */ + + /* fast test for majority of non-wide scripts */ + if (ucs < 0x1100) + return 1; + + return 1 + ((ucs >= 0x1100 && ucs <= 0x115f) || /* Hangul Jamo */ + + (ucs >= 0x2e80 && ucs <= 0xa4cf + && (ucs & ~0x0011) != 0x300a && ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ + (ucs >= 0xffe0 && ucs <= 0xffe6)); +} + + +int wcswidth(const wchar_t * pwcs, size_t n) +{ + int w, width = 0; + + for (; *pwcs && n-- > 0; pwcs++) + if ((w = wcwidth(*pwcs)) < 0) + return -1; + else + width += w; + + return width; +} diff --git a/windlg.c b/windlg.c index 2f9ca56c..99cd9c39 100644 --- a/windlg.c +++ b/windlg.c @@ -128,7 +128,7 @@ static int CALLBACK LogProc(HWND hwnd, UINT msg, memcpy(p, sel_nl, sizeof(sel_nl)); p += sizeof(sel_nl); } - write_clip(clipdata, size, TRUE); + write_aclip(clipdata, size, TRUE); sfree(clipdata); } sfree(selitems); @@ -486,18 +486,14 @@ enum { IDCX_ABOUT = IDC_TITLE_TRANSLATION, IDC_BOX_TRANSLATION1, IDC_BOX_TRANSLATION2, - IDC_BOX_TRANSLATION3, - IDC_XLATSTATIC, - IDC_NOXLAT, - IDC_KOI8WIN1251, - IDC_88592WIN1250, - IDC_88592CP852, - IDC_CAPSLOCKCYR, + IDC_CODEPAGESTATIC, + IDC_CODEPAGE, IDC_VTSTATIC, IDC_VTXWINDOWS, IDC_VTOEMANSI, IDC_VTOEMONLY, IDC_VTPOORMAN, + IDC_VTUNICODE, translationpanelend, tunnelspanelstart, @@ -691,7 +687,7 @@ static void init_dlg_ctrls(HWND hwnd) SendDlgItemMessage(hwnd, IDC_CCLIST, LB_SETTABSTOPS, 4, (LPARAM) tabs); } - for (i = 0; i < 256; i++) { + for (i = 0; i < 128; i++) { char str[100]; sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i, (i >= 0x21 && i != 0x7F) ? i : ' ', cfg.wordness[i]); @@ -717,15 +713,12 @@ static void init_dlg_ctrls(HWND hwnd) SetDlgItemInt(hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE); SetDlgItemInt(hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE); - CheckRadioButton(hwnd, IDC_NOXLAT, IDC_88592CP852, - cfg.xlat_88592w1250 ? IDC_88592WIN1250 : - cfg.xlat_88592cp852 ? IDC_88592CP852 : - cfg.xlat_enablekoiwin ? IDC_KOI8WIN1251 : IDC_NOXLAT); - CheckDlgButton(hwnd, IDC_CAPSLOCKCYR, cfg.xlat_capslockcyr); - CheckRadioButton(hwnd, IDC_VTXWINDOWS, IDC_VTPOORMAN, + SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage); + CheckRadioButton(hwnd, IDC_VTXWINDOWS, IDC_VTUNICODE, cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS : cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI : cfg.vtmode == VT_OEMONLY ? IDC_VTOEMONLY : + cfg.vtmode == VT_UNICODE ? IDC_VTUNICODE : IDC_VTPOORMAN); CheckDlgButton(hwnd, IDC_X11_FORWARD, cfg.x11_forward); @@ -781,7 +774,7 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL); if (backends[3].backend == NULL) { /* this is PuTTYtel, so only three protocols available */ - radioline(&cp, "Protocol:", IDC_PROTSTATIC, 4, + radioline(&cp, "Protocol:", IDC_PROTSTATIC, 3, "&Raw", IDC_PROTRAW, "&Telnet", IDC_PROTTELNET, "Rlog&in", IDC_PROTRLOGIN, NULL); @@ -1018,21 +1011,12 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) "Use font in &both ANSI and OEM modes", IDC_VTOEMANSI, "Use font in O&EM mode only", IDC_VTOEMONLY, "&Poor man's line drawing (" "+" ", " "-" " and " "|" ")", - IDC_VTPOORMAN, NULL); + IDC_VTPOORMAN, "&Unicode mode", IDC_VTUNICODE, NULL); endbox(&cp); beginbox(&cp, "Enable character set translation on received data", IDC_BOX_TRANSLATION2); - radiobig(&cp, - "Character set &translation:", IDC_XLATSTATIC, - "None", IDC_NOXLAT, - "KOI8 / Win-1251", IDC_KOI8WIN1251, - "ISO-8859-2 / Win-1250", IDC_88592WIN1250, - "ISO-8859-2 / CP852", IDC_88592CP852, NULL); - endbox(&cp); - beginbox(&cp, "Enable character set translation on input data", - IDC_BOX_TRANSLATION3); - checkbox(&cp, "CAP&S LOCK acts as cyrillic switch", - IDC_CAPSLOCKCYR); + multiedit(&cp, "Line codepage:", IDC_CODEPAGESTATIC, + IDC_CODEPAGE, 100, NULL); endbox(&cp); } @@ -2194,7 +2178,7 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg, if (!ok) MessageBeep(0); else { - for (i = 0; i < 256; i++) + for (i = 0; i < 128; i++) if (SendDlgItemMessage (hwnd, IDC_CCLIST, LB_GETSEL, i, 0)) { char str[100]; @@ -2288,34 +2272,44 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg, } } break; - case IDC_NOXLAT: - case IDC_KOI8WIN1251: - case IDC_88592WIN1250: - case IDC_88592CP852: - cfg.xlat_enablekoiwin = - IsDlgButtonChecked(hwnd, IDC_KOI8WIN1251); - cfg.xlat_88592w1250 = - IsDlgButtonChecked(hwnd, IDC_88592WIN1250); - cfg.xlat_88592cp852 = - IsDlgButtonChecked(hwnd, IDC_88592CP852); - break; - case IDC_CAPSLOCKCYR: - if (HIWORD(wParam) == BN_CLICKED || - HIWORD(wParam) == BN_DOUBLECLICKED) { - cfg.xlat_capslockcyr = - IsDlgButtonChecked(hwnd, IDC_CAPSLOCKCYR); + case IDC_CODEPAGE: + if (HIWORD(wParam) == EN_CHANGE) + GetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage, + sizeof(cfg.line_codepage) - 1); + if (HIWORD(wParam) == EN_KILLFOCUS) { + int cp = decode_codepage(cfg.line_codepage); + char buf[256]; + if (cp < -1) { + if (cp == -2) + sprintf(buf, + "Unable to identify character set '%s', " + "translation disabled.", + cfg.line_codepage); + if (cp == -3) + sprintf(buf, + "Character set '%s' is a DBCS, " + "translation is not available.", + cfg.line_codepage); + MessageBox(hwnd, buf, "PuTTY Error", + MB_ICONERROR | MB_OK); + } + strcpy(cfg.line_codepage, cp_name(cp)); + SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage); } break; case IDC_VTXWINDOWS: case IDC_VTOEMANSI: case IDC_VTOEMONLY: case IDC_VTPOORMAN: + case IDC_VTUNICODE: cfg.vtmode = (IsDlgButtonChecked(hwnd, IDC_VTXWINDOWS) ? VT_XWINDOWS : IsDlgButtonChecked(hwnd, IDC_VTOEMANSI) ? VT_OEMANSI : IsDlgButtonChecked(hwnd, IDC_VTOEMONLY) ? VT_OEMONLY : + IsDlgButtonChecked(hwnd, + IDC_VTUNICODE) ? VT_UNICODE : VT_POORMAN); break; case IDC_X11_FORWARD: diff --git a/window.c b/window.c index 48ba35b7..37b3a007 100644 --- a/window.c +++ b/window.c @@ -63,6 +63,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, static void cfgtopalette(void); static void init_palette(void); static void init_fonts(int); +static void another_font(int); +static void deinit_fonts(void); static int extra_width, extra_height; @@ -77,12 +79,20 @@ static time_t last_movement = 0; #define FONT_BOLD 1 #define FONT_UNDERLINE 2 #define FONT_BOLDUND 3 -#define FONT_OEM 4 -#define FONT_OEMBOLD 5 -#define FONT_OEMBOLDUND 6 -#define FONT_OEMUND 7 -static HFONT fonts[8]; -static int font_needs_hand_underlining; +#define FONT_WIDE 0x04 +#define FONT_HIGH 0x08 +#define FONT_NARROW 0x10 +#define FONT_OEM 0x20 +#define FONT_OEMBOLD 0x21 +#define FONT_OEMUND 0x22 +#define FONT_OEMBOLDUND 0x23 +#define FONT_MSGOTHIC 0x40 +#define FONT_MINGLIU 0x60 +#define FONT_GULIMCHE 0x80 +#define FONT_MAXNO 0x8F +#define FONT_SHIFT 5 +static HFONT fonts[FONT_MAXNO]; +static int fontflag[FONT_MAXNO]; static enum { BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT } bold_mode; @@ -642,12 +652,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * Clean up. */ - { - int i; - for (i = 0; i < 8; i++) - if (fonts[i]) - DeleteObject(fonts[i]); - } + deinit_fonts(); sfree(logpal); if (pal) DeleteObject(pal); @@ -811,8 +816,11 @@ static void init_palette(void) } /* - * Initialise all the fonts we will need. There may be as many as - * eight or as few as one. We also: + * Initialise all the fonts we will need initially. There may be as many as + * three or as few as one. The other (poentially) twentyone fonts are done + * if/when they are needed. + * + * We also: * * - check the font width and height, correcting our guesses if * necessary. @@ -827,16 +835,13 @@ static void init_palette(void) static void init_fonts(int pick_width) { TEXTMETRIC tm; + CPINFO cpinfo; + int fontsize[3]; int i; - int fsize[8]; HDC hdc; int fw_dontcare, fw_bold; - int firstchar = ' '; -#ifdef CHECKOEMFONT - font_messup: -#endif - for (i = 0; i < 8; i++) + for (i = 0; i < FONT_MAXNO; i++) fonts[i] = NULL; if (cfg.fontisbold) { @@ -862,152 +867,177 @@ static void init_fonts(int pick_width) CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \ FIXED_PITCH | FF_DONTCARE, cfg.font) - if (cfg.vtmode != VT_OEMONLY) { - f(FONT_NORMAL, cfg.fontcharset, fw_dontcare, FALSE); + f(FONT_NORMAL, cfg.fontcharset, fw_dontcare, FALSE); - SelectObject(hdc, fonts[FONT_NORMAL]); - GetTextMetrics(hdc, &tm); - font_height = tm.tmHeight; - font_width = tm.tmAveCharWidth; + SelectObject(hdc, fonts[FONT_NORMAL]); + GetTextMetrics(hdc, &tm); + font_height = tm.tmHeight; + font_width = tm.tmAveCharWidth; - f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE); + { + CHARSETINFO info; + DWORD cset = tm.tmCharSet; + memset(&info, 0xFF, sizeof(info)); - /* - * Some fonts, e.g. 9-pt Courier, draw their underlines - * outside their character cell. We successfully prevent - * screen corruption by clipping the text output, but then - * we lose the underline completely. Here we try to work - * out whether this is such a font, and if it is, we set a - * flag that causes underlines to be drawn by hand. - * - * Having tried other more sophisticated approaches (such - * as examining the TEXTMETRIC structure or requesting the - * height of a string), I think we'll do this the brute - * force way: we create a small bitmap, draw an underlined - * space on it, and test to see whether any pixels are - * foreground-coloured. (Since we expect the underline to - * go all the way across the character cell, we only search - * down a single column of the bitmap, half way across.) - */ - { - HDC und_dc; - HBITMAP und_bm, und_oldbm; - int i, gotit; - COLORREF c; - - und_dc = CreateCompatibleDC(hdc); - und_bm = CreateCompatibleBitmap(hdc, font_width, font_height); - und_oldbm = SelectObject(und_dc, und_bm); - SelectObject(und_dc, fonts[FONT_UNDERLINE]); - SetTextAlign(und_dc, TA_TOP | TA_LEFT | TA_NOUPDATECP); - SetTextColor(und_dc, RGB(255, 255, 255)); - SetBkColor(und_dc, RGB(0, 0, 0)); - SetBkMode(und_dc, OPAQUE); - ExtTextOut(und_dc, 0, 0, ETO_OPAQUE, NULL, " ", 1, NULL); - gotit = FALSE; - for (i = 0; i < font_height; i++) { - c = GetPixel(und_dc, font_width / 2, i); - if (c != RGB(0, 0, 0)) - gotit = TRUE; - } - SelectObject(und_dc, und_oldbm); - DeleteObject(und_bm); - DeleteDC(und_dc); - font_needs_hand_underlining = !gotit; - } + /* !!! Yes the next line is right */ + if (cset == OEM_CHARSET) + font_codepage = GetOEMCP(); + else + if (TranslateCharsetInfo + ((DWORD *) cset, &info, TCI_SRCCHARSET)) font_codepage = + info.ciACP; + else + font_codepage = -1; - if (bold_mode == BOLD_FONT) { - f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE); - f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE); - } + GetCPInfo(font_codepage, &cpinfo); + dbcs_screenfont = (cpinfo.MaxCharSize > 1); + } - if (cfg.vtmode == VT_OEMANSI) { - f(FONT_OEM, OEM_CHARSET, fw_dontcare, FALSE); - f(FONT_OEMUND, OEM_CHARSET, fw_dontcare, TRUE); + f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE); - if (bold_mode == BOLD_FONT) { - f(FONT_OEMBOLD, OEM_CHARSET, fw_bold, FALSE); - f(FONT_OEMBOLDUND, OEM_CHARSET, fw_bold, TRUE); - } + /* + * Some fonts, e.g. 9-pt Courier, draw their underlines + * outside their character cell. We successfully prevent + * screen corruption by clipping the text output, but then + * we lose the underline completely. Here we try to work + * out whether this is such a font, and if it is, we set a + * flag that causes underlines to be drawn by hand. + * + * Having tried other more sophisticated approaches (such + * as examining the TEXTMETRIC structure or requesting the + * height of a string), I think we'll do this the brute + * force way: we create a small bitmap, draw an underlined + * space on it, and test to see whether any pixels are + * foreground-coloured. (Since we expect the underline to + * go all the way across the character cell, we only search + * down a single column of the bitmap, half way across.) + */ + { + HDC und_dc; + HBITMAP und_bm, und_oldbm; + int i, gotit; + COLORREF c; + + und_dc = CreateCompatibleDC(hdc); + und_bm = CreateCompatibleBitmap(hdc, font_width, font_height); + und_oldbm = SelectObject(und_dc, und_bm); + SelectObject(und_dc, fonts[FONT_UNDERLINE]); + SetTextAlign(und_dc, TA_TOP | TA_LEFT | TA_NOUPDATECP); + SetTextColor(und_dc, RGB(255, 255, 255)); + SetBkColor(und_dc, RGB(0, 0, 0)); + SetBkMode(und_dc, OPAQUE); + ExtTextOut(und_dc, 0, 0, ETO_OPAQUE, NULL, " ", 1, NULL); + gotit = FALSE; + for (i = 0; i < font_height; i++) { + c = GetPixel(und_dc, font_width / 2, i); + if (c != RGB(0, 0, 0)) + gotit = TRUE; + } + SelectObject(und_dc, und_oldbm); + DeleteObject(und_bm); + DeleteDC(und_dc); + if (!gotit) { + und_mode = UND_LINE; + DeleteObject(fonts[FONT_UNDERLINE]); + fonts[FONT_UNDERLINE] = 0; } - } else { - f(FONT_OEM, cfg.fontcharset, fw_dontcare, FALSE); - - SelectObject(hdc, fonts[FONT_OEM]); - GetTextMetrics(hdc, &tm); - font_height = tm.tmHeight; - font_width = tm.tmAveCharWidth; - - f(FONT_OEMUND, cfg.fontcharset, fw_dontcare, TRUE); + } - if (bold_mode == BOLD_FONT) { - f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE); - f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE); - } + if (bold_mode == BOLD_FONT) { + f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE); } #undef f descent = tm.tmAscent + 1; if (descent >= font_height) descent = font_height - 1; - firstchar = tm.tmFirstChar; - for (i = 0; i < 8; i++) { + for (i = 0; i < 3; i++) { if (fonts[i]) { if (SelectObject(hdc, fonts[i]) && GetTextMetrics(hdc, &tm)) - fsize[i] = tm.tmAveCharWidth + 256 * tm.tmHeight; + fontsize[i] = tm.tmAveCharWidth + 256 * tm.tmHeight; else - fsize[i] = -i; + fontsize[i] = -i; } else - fsize[i] = -i; + fontsize[i] = -i; } ReleaseDC(hwnd, hdc); - /* ... This is wrong in OEM only mode */ - if (fsize[FONT_UNDERLINE] != fsize[FONT_NORMAL] || - (bold_mode == BOLD_FONT && - fsize[FONT_BOLDUND] != fsize[FONT_BOLD])) { + if (fontsize[FONT_UNDERLINE] != fontsize[FONT_NORMAL]) { und_mode = UND_LINE; DeleteObject(fonts[FONT_UNDERLINE]); - if (bold_mode == BOLD_FONT) - DeleteObject(fonts[FONT_BOLDUND]); + fonts[FONT_UNDERLINE] = 0; } - if (bold_mode == BOLD_FONT && fsize[FONT_BOLD] != fsize[FONT_NORMAL]) { + if (bold_mode == BOLD_FONT && + fontsize[FONT_BOLD] != fontsize[FONT_NORMAL]) { bold_mode = BOLD_SHADOW; DeleteObject(fonts[FONT_BOLD]); - if (und_mode == UND_FONT) - DeleteObject(fonts[FONT_BOLDUND]); + fonts[FONT_BOLD] = 0; } -#ifdef CHECKOEMFONT - /* With the fascist font painting it doesn't matter if the linedraw font - * isn't exactly the right size anymore so we don't have to check this. - */ - if (cfg.vtmode == VT_OEMANSI && fsize[FONT_OEM] != fsize[FONT_NORMAL]) { - if (cfg.fontcharset == OEM_CHARSET) { - MessageBox(NULL, "The OEM and ANSI versions of this font are\n" - "different sizes. Using OEM-only mode instead", - "Font Size Mismatch", MB_ICONINFORMATION | MB_OK); - cfg.vtmode = VT_OEMONLY; - } else if (firstchar < ' ') { - MessageBox(NULL, "The OEM and ANSI versions of this font are\n" - "different sizes. Using XTerm mode instead", - "Font Size Mismatch", MB_ICONINFORMATION | MB_OK); - cfg.vtmode = VT_XWINDOWS; - } else { - MessageBox(NULL, "The OEM and ANSI versions of this font are\n" - "different sizes. Using ISO8859-1 mode instead", - "Font Size Mismatch", MB_ICONINFORMATION | MB_OK); - cfg.vtmode = VT_POORMAN; - } + fontflag[0] = fontflag[1] = fontflag[2] = 1; + + init_ucs_tables(); +} + +static void another_font(int fontno) +{ + int basefont; + int fw_dontcare, fw_bold; + int c, u, w, x; + char *s; + + if (fontno < 0 || fontno >= FONT_MAXNO || fontflag[fontno]) + return; + + basefont = (fontno & ~(FONT_BOLDUND)); + if (basefont != fontno && !fontflag[basefont]) + another_font(basefont); + + if (cfg.fontisbold) { + fw_dontcare = FW_BOLD; + fw_bold = FW_HEAVY; + } else { + fw_dontcare = FW_DONTCARE; + fw_bold = FW_BOLD; + } + + c = cfg.fontcharset; + w = fw_dontcare; + u = FALSE; + s = cfg.font; + x = font_width; + + if (fontno & FONT_WIDE) + x *= 2; + if (fontno & FONT_NARROW) + x /= 2; + if (fontno & FONT_OEM) + c = OEM_CHARSET; + if (fontno & FONT_BOLD) + w = fw_bold; + if (fontno & FONT_UNDERLINE) + u = TRUE; + + fonts[fontno] = + CreateFont(font_height * (1 + !!(fontno & FONT_HIGH)), x, 0, 0, w, + FALSE, u, FALSE, c, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + FIXED_PITCH | FF_DONTCARE, s); + + fontflag[fontno] = 1; +} - for (i = 0; i < 8; i++) - if (fonts[i]) - DeleteObject(fonts[i]); - goto font_messup; +static void deinit_fonts(void) +{ + int i; + for (i = 0; i < FONT_MAXNO; i++) { + if (fonts[i]) + DeleteObject(fonts[i]); + fonts[i] = 0; + fontflag[i] = 0; } -#endif } void request_resize(int w, int h, int refont) @@ -1018,25 +1048,13 @@ void request_resize(int w, int h, int refont) if (IsZoomed(hwnd)) return; -#ifdef CHECKOEMFONT - /* Don't do this in OEMANSI, you may get disable messages */ - if (refont && w != cols && (cols == 80 || cols == 132) - && cfg.vtmode != VT_OEMANSI) -#else - if (refont && w != cols && (cols == 80 || cols == 132)) -#endif - { + if (refont && w != cols && (cols == 80 || cols == 132)) { /* If font width too big for screen should we shrink the font more ? */ if (w == 132) font_width = ((font_width * cols + w / 2) / w); else font_width = 0; - { - int i; - for (i = 0; i < 8; i++) - if (fonts[i]) - DeleteObject(fonts[i]); - } + deinit_fonts(); bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT; und_mode = UND_FONT; init_fonts(font_width); @@ -1267,12 +1285,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } just_reconfigged = TRUE; - { - int i; - for (i = 0; i < 8; i++) - if (fonts[i]) - DeleteObject(fonts[i]); - } + deinit_fonts(); bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT; und_mode = UND_FONT; init_fonts(0); @@ -1823,14 +1836,33 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } return 0; - case WM_IME_CHAR: + case WM_INPUTLANGCHANGE: { + /* wParam == Font number */ + /* lParam == Locale */ + char lbuf[20]; + HKL NewInputLocale = (HKL) lParam; + + // lParam == GetKeyboardLayout(0); + + GetLocaleInfo(LOWORD(NewInputLocale), + LOCALE_IDEFAULTANSICODEPAGE, lbuf, sizeof(lbuf)); + + kbd_codepage = atoi(lbuf); + } + break; + case WM_IME_CHAR: + if (wParam & 0xFF00) { unsigned char buf[2]; buf[1] = wParam; buf[0] = wParam >> 8; - ldisc_send(buf, 2); + lpage_send(kbd_codepage, buf, 2); + } else { + char c = (unsigned char) wParam; + lpage_send(kbd_codepage, &c, 1); } + return (0); case WM_CHAR: case WM_SYSCHAR: /* @@ -1840,8 +1872,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * we're ready to cope. */ { - char c = xlat_kbd2tty((unsigned char) wParam); - ldisc_send(&c, 1); + char c = (unsigned char)wParam; + lpage_send(CP_ACP, &c, 1); } return 0; case WM_SETCURSOR: @@ -1881,9 +1913,14 @@ void do_text(Context ctx, int x, int y, char *text, int len, RECT line_box; int force_manual_underline = 0; int fnt_width = font_width * (1 + (lattr != LATTR_NORM)); - static int *IpDx = 0, IpDxLEN = 0;; + int char_width = fnt_width; + int text_adjust = 0; + static int *IpDx = 0, IpDxLEN = 0; + + if (attr & ATTR_WIDE) + char_width *= 2; - if (len > IpDxLEN || IpDx[0] != fnt_width) { + if (len > IpDxLEN || IpDx[0] != char_width) { int i; if (len > IpDxLEN) { sfree(IpDx); @@ -1891,123 +1928,81 @@ void do_text(Context ctx, int x, int y, char *text, int len, IpDxLEN = (len + 16); } for (i = 0; i < IpDxLEN; i++) - IpDx[i] = fnt_width; + IpDx[i] = char_width; } x *= fnt_width; y *= font_height; - if ((attr & ATTR_ACTCURS) && cfg.cursor_type == 0) { - attr &= (bold_mode == BOLD_COLOURS ? 0x300200 : 0x300300); + if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || big_cursor)) { + attr &= ATTR_CUR_AND | (bold_mode != BOLD_COLOURS ? ATTR_BOLD : 0); attr ^= ATTR_CUR_XOR; } nfont = 0; - if (cfg.vtmode == VT_OEMONLY) - nfont |= FONT_OEM; - - /* - * Map high-half characters in order to approximate ISO using - * OEM character set. No characters are missing if the OEM codepage - * is CP850. - */ - if (nfont & FONT_OEM) { - int i; - for (i = 0; i < len; i++) - if (text[i] >= '\xA0' && text[i] <= '\xFF') { -#if 0 - /* This is CP850 ... perfect translation */ - static const char oemhighhalf[] = "\x20\xAD\xBD\x9C\xCF\xBE\xDD\xF5" /* A0-A7 */ - "\xF9\xB8\xA6\xAE\xAA\xF0\xA9\xEE" /* A8-AF */ - "\xF8\xF1\xFD\xFC\xEF\xE6\xF4\xFA" /* B0-B7 */ - "\xF7\xFB\xA7\xAF\xAC\xAB\xF3\xA8" /* B8-BF */ - "\xB7\xB5\xB6\xC7\x8E\x8F\x92\x80" /* C0-C7 */ - "\xD4\x90\xD2\xD3\xDE\xD6\xD7\xD8" /* C8-CF */ - "\xD1\xA5\xE3\xE0\xE2\xE5\x99\x9E" /* D0-D7 */ - "\x9D\xEB\xE9\xEA\x9A\xED\xE8\xE1" /* D8-DF */ - "\x85\xA0\x83\xC6\x84\x86\x91\x87" /* E0-E7 */ - "\x8A\x82\x88\x89\x8D\xA1\x8C\x8B" /* E8-EF */ - "\xD0\xA4\x95\xA2\x93\xE4\x94\xF6" /* F0-F7 */ - "\x9B\x97\xA3\x96\x81\xEC\xE7\x98" /* F8-FF */ - ; -#endif - /* This is CP437 ... junk translation */ - static const unsigned char oemhighhalf[] = { - 0x20, 0xad, 0x9b, 0x9c, 0x6f, 0x9d, 0x7c, 0x15, - 0x22, 0x43, 0xa6, 0xae, 0xaa, 0x2d, 0x52, 0xc4, - 0xf8, 0xf1, 0xfd, 0x33, 0x27, 0xe6, 0x14, 0xfa, - 0x2c, 0x31, 0xa7, 0xaf, 0xac, 0xab, 0x2f, 0xa8, - 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80, - 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, - 0x44, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x78, - 0xed, 0x55, 0x55, 0x55, 0x9a, 0x59, 0x50, 0xe1, - 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87, - 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, - 0x0b, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0xf6, - 0xed, 0x97, 0xa3, 0x96, 0x81, 0x79, 0x70, 0x98 - }; - - text[i] = oemhighhalf[(unsigned char) text[i] - 0xA0]; - } - } - - if (attr & ATTR_LINEDRW) { - int i; - /* ISO 8859-1 */ - static const char poorman[] = - "*#****\xB0\xB1**+++++-----++++|****\xA3\xB7"; - - /* CP437 */ - static const char oemmap_437[] = - "\x04\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5" - "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3\xF3\xF2\xE3*\x9C\xFA"; - - /* CP850 */ - static const char oemmap_850[] = - "\x04\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5" - "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3****\x9C\xFA"; - - /* Poor windows font ... eg: windows courier */ - static const char oemmap[] = - "*\xB1****\xF8\xF1**\xD9\xBF\xDA\xC0\xC5" - "\xC4\xC4\xC4\xC4\xC4\xC3\xB4\xC1\xC2\xB3****\x9C\xFA"; - - /* - * Line drawing mapping: map ` thru ~ (0x60 thru 0x7E) to - * VT100 line drawing chars; everything else stays normal. - * - * Actually '_' maps to space too, but that's done before. - */ - switch (cfg.vtmode) { - case VT_XWINDOWS: - for (i = 0; i < len; i++) - if (text[i] >= '\x60' && text[i] <= '\x7E') - text[i] += '\x01' - '\x60'; + if (cfg.vtmode == VT_POORMAN && lattr != LATTR_NORM) { + /* Assume a poorman font is borken in other ways too. */ + lattr = LATTR_WIDE; + } else + switch (lattr) { + case LATTR_NORM: + break; + case LATTR_WIDE: + nfont |= FONT_WIDE; + break; + default: + nfont |= FONT_WIDE + FONT_HIGH; break; - case VT_OEMANSI: - /* Make sure we actually have an OEM font */ - if (fonts[nfont | FONT_OEM]) { - case VT_OEMONLY: - nfont |= FONT_OEM; - for (i = 0; i < len; i++) - if (text[i] >= '\x60' && text[i] <= '\x7E') - text[i] = oemmap[(unsigned char) text[i] - 0x60]; + } + + /* Special hack for the VT100 linedraw glyphs. */ + if ((attr & CSET_MASK) == 0x2300) { + if (!dbcs_screenfont && + text[0] >= (char) 0xBA && text[0] <= (char) 0xBD) { + switch ((unsigned char) (text[0])) { + case 0xBA: + text_adjust = -2 * font_height / 5; + break; + case 0xBB: + text_adjust = -1 * font_height / 5; + break; + case 0xBC: + text_adjust = font_height / 5; + break; + case 0xBD: + text_adjust = 2 * font_height / 5; break; } - case VT_POORMAN: - for (i = 0; i < len; i++) - if (text[i] >= '\x60' && text[i] <= '\x7E') - text[i] = poorman[(unsigned char) text[i] - 0x60]; - break; + if (lattr == LATTR_TOP || lattr == LATTR_BOT) + text_adjust *= 2; + attr &= ~CSET_MASK; + text[0] = (char) (unitab_xterm['q'] & CHAR_MASK); + attr |= (unitab_xterm['q'] & CSET_MASK); + if (attr & ATTR_UNDER) { + attr &= ~ATTR_UNDER; + force_manual_underline = 1; + } } } + /* Anything left as an original character set is unprintable. */ + if (DIRECT_CHAR(attr)) { + attr &= ~CSET_MASK; + attr |= 0xFF00; + memset(text, 0xFF, len); + } + + /* OEM CP */ + if ((attr & CSET_MASK) == ATTR_OEMCP) + nfont |= FONT_OEM; + nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); nbg = 2 * ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD)) nfont |= FONT_BOLD; if (und_mode == UND_FONT && (attr & ATTR_UNDER)) nfont |= FONT_UNDERLINE; + another_font(nfont); if (!fonts[nfont]) { if (nfont & FONT_UNDERLINE) force_manual_underline = 1; @@ -2015,8 +2010,9 @@ void do_text(Context ctx, int x, int y, char *text, int len, nfont &= ~(FONT_BOLD | FONT_UNDERLINE); } - if (font_needs_hand_underlining && (attr & ATTR_UNDER)) - force_manual_underline = 1; + another_font(nfont); + if (!fonts[nfont]) + nfont = FONT_NORMAL; if (attr & ATTR_REVERSE) { t = nfg; nfg = nbg; @@ -2034,62 +2030,151 @@ void do_text(Context ctx, int x, int y, char *text, int len, SetBkMode(hdc, OPAQUE); line_box.left = x; line_box.top = y; - line_box.right = x + fnt_width * len; + line_box.right = x + char_width * len; line_box.bottom = y + font_height; - ExtTextOut(hdc, x, y, ETO_CLIPPED | ETO_OPAQUE, &line_box, text, len, - IpDx); - if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { - SetBkMode(hdc, TRANSPARENT); - - /* GRR: This draws the character outside it's box and can leave - * 'droppings' even with the clip box! I suppose I could loop it - * one character at a time ... yuk. - * - * Or ... I could do a test print with "W", and use +1 or -1 for this - * shift depending on if the leftmost column is blank... - */ - ExtTextOut(hdc, x - 1, y, ETO_CLIPPED, &line_box, text, len, IpDx); + + /* We're using a private area for direct to font. (512 chars.) */ + if (dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) { + /* Ho Hum, dbcs fonts are a PITA! */ + /* To display on W9x I have to convert to UCS */ + static wchar_t *uni_buf = 0; + static int uni_len = 0; + int nlen; + if (len > uni_len) { + sfree(uni_buf); + uni_buf = smalloc((uni_len = len) * sizeof(wchar_t)); + } + nlen = MultiByteToWideChar(font_codepage, MB_USEGLYPHCHARS, + text, len, uni_buf, uni_len); + + if (nlen <= 0) + return; /* Eeek! */ + + ExtTextOutW(hdc, x, + y - font_height * (lattr == LATTR_BOT) + text_adjust, + ETO_CLIPPED | ETO_OPAQUE, &line_box, uni_buf, nlen, 0); + if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { + SetBkMode(hdc, TRANSPARENT); + ExtTextOutW(hdc, x - 1, + y - font_height * (lattr == + LATTR_BOT) + text_adjust, + ETO_CLIPPED, &line_box, uni_buf, nlen, 0); + } + } else if (DIRECT_FONT(attr)) { + ExtTextOut(hdc, x, + y - font_height * (lattr == LATTR_BOT) + text_adjust, + ETO_CLIPPED | ETO_OPAQUE, &line_box, text, len, IpDx); + if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { + SetBkMode(hdc, TRANSPARENT); + + /* GRR: This draws the character outside it's box and can leave + * 'droppings' even with the clip box! I suppose I could loop it + * one character at a time ... yuk. + * + * Or ... I could do a test print with "W", and use +1 or -1 for this + * shift depending on if the leftmost column is blank... + */ + ExtTextOut(hdc, x - 1, + y - font_height * (lattr == + LATTR_BOT) + text_adjust, + ETO_CLIPPED, &line_box, text, len, IpDx); + } + } else { + /* And 'normal' unicode characters */ + static WCHAR *wbuf = NULL; + static int wlen = 0; + int i; + if (wlen < len) { + sfree(wbuf); + wlen = len; + wbuf = smalloc(wlen * sizeof(WCHAR)); + } + for (i = 0; i < len; i++) + wbuf[i] = (WCHAR) ((attr & CSET_MASK) + (text[i] & CHAR_MASK)); + + ExtTextOutW(hdc, x, + y - font_height * (lattr == LATTR_BOT) + text_adjust, + ETO_CLIPPED | ETO_OPAQUE, &line_box, wbuf, len, IpDx); + + /* And the shadow bold hack. */ + if (bold_mode == BOLD_SHADOW) { + SetBkMode(hdc, TRANSPARENT); + ExtTextOutW(hdc, x - 1, + y - font_height * (lattr == + LATTR_BOT) + text_adjust, + ETO_CLIPPED, &line_box, wbuf, len, IpDx); + } } - if (force_manual_underline || - (und_mode == UND_LINE && (attr & ATTR_UNDER))) { + if (lattr != LATTR_TOP && (force_manual_underline || + (und_mode == UND_LINE + && (attr & ATTR_UNDER)))) { HPEN oldpen; + int dec = descent; + if (lattr == LATTR_BOT) + dec = dec * 2 - font_height; + oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, fg)); - MoveToEx(hdc, x, y + descent, NULL); - LineTo(hdc, x + len * fnt_width, y + descent); + MoveToEx(hdc, x, y + dec, NULL); + LineTo(hdc, x + len * char_width, y + dec); oldpen = SelectObject(hdc, oldpen); DeleteObject(oldpen); } - if ((attr & ATTR_PASCURS) && cfg.cursor_type == 0) { +} + +void do_cursor(Context ctx, int x, int y, char *text, int len, + unsigned long attr, int lattr) +{ + + int fnt_width; + int char_width; + HDC hdc = ctx; + int ctype = cfg.cursor_type; + + if ((attr & TATTR_ACTCURS) && (ctype == 0 || big_cursor)) { + if (((attr & CSET_MASK) | (unsigned char) *text) != UCSWIDE) { + do_text(ctx, x, y, text, len, attr, lattr); + return; + } + ctype = 2; + attr |= TATTR_RIGHTCURS; + } + + fnt_width = char_width = font_width * (1 + (lattr != LATTR_NORM)); + if (attr & ATTR_WIDE) + char_width *= 2; + x *= fnt_width; + y *= font_height; + + if ((attr & TATTR_PASCURS) && (ctype == 0 || big_cursor)) { POINT pts[5]; HPEN oldpen; pts[0].x = pts[1].x = pts[4].x = x; - pts[2].x = pts[3].x = x + fnt_width - 1; + pts[2].x = pts[3].x = x + char_width - 1; pts[0].y = pts[3].y = pts[4].y = y; pts[1].y = pts[2].y = y + font_height - 1; oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23])); Polyline(hdc, pts, 5); oldpen = SelectObject(hdc, oldpen); DeleteObject(oldpen); - } - if ((attr & (ATTR_ACTCURS | ATTR_PASCURS)) && cfg.cursor_type != 0) { + } else if ((attr & (TATTR_ACTCURS | TATTR_PASCURS)) && ctype != 0) { int startx, starty, dx, dy, length, i; - if (cfg.cursor_type == 1) { + if (ctype == 1) { startx = x; starty = y + descent; dx = 1; dy = 0; - length = fnt_width; + length = char_width; } else { int xadjust = 0; - if (attr & ATTR_RIGHTCURS) - xadjust = fnt_width - 1; + if (attr & TATTR_RIGHTCURS) + xadjust = char_width - 1; startx = x + xadjust; starty = y; dx = 0; dy = 1; length = font_height; } - if (attr & ATTR_ACTCURS) { + if (attr & TATTR_ACTCURS) { HPEN oldpen; oldpen = SelectObject(hdc, CreatePen(PS_SOLID, 0, colours[23])); @@ -2109,55 +2194,6 @@ void do_text(Context ctx, int x, int y, char *text, int len, } } -static int check_compose(int first, int second) -{ - - static char *composetbl[] = { - "++#", "AA@", "(([", "//\\", "))]", "(-{", "-)}", "/^|", "!!¡", - "C/¢", - "C|¢", "L-£", "L=£", "XO¤", "X0¤", "Y-¥", "Y=¥", "||¦", "SO§", - "S!§", - "S0§", "\"\"¨", "CO©", "C0©", "A_ª", "<<«", ",-¬", "--­", "RO®", - "-^¯", "0^°", "+-±", "2^²", "3^³", "''´", "/Uµ", "P!¶", ".^·", - ",,¸", - "1^¹", "O_º", ">>»", "14¼", "12½", "34¾", "??¿", "`AÀ", "'AÁ", - "^AÂ", - "~AÃ", "\"AÄ", "*AÅ", "AEÆ", ",CÇ", "`EÈ", "'EÉ", "^EÊ", "\"EË", - "`IÌ", "'IÍ", "^IÎ", "\"IÏ", "-DÐ", "~NÑ", "`OÒ", "'OÓ", "^OÔ", - "~OÕ", "\"OÖ", "XX×", "/OØ", "`UÙ", "'UÚ", "^UÛ", "\"UÜ", "'YÝ", - "HTÞ", "ssß", "`aà", "'aá", "^aâ", "~aã", "\"aä", "*aå", "aeæ", - ",cç", - "`eè", "'eé", "^eê", "\"eë", "`iì", "'ií", "^iî", "\"iï", "-dð", - "~nñ", - "`oò", "'oó", "^oô", "~oõ", "\"oö", ":-÷", "o/ø", "`uù", "'uú", - "^uû", - "\"uü", "'yý", "htþ", "\"yÿ", - 0 - }; - - char **c; - static int recurse = 0; - int nc = -1; - - for (c = composetbl; *c; c++) { - if ((*c)[0] == first && (*c)[1] == second) { - return (*c)[2] & 0xFF; - } - } - - if (recurse == 0) { - recurse = 1; - nc = check_compose(second, first); - if (nc == -1) - nc = check_compose(toupper(first), toupper(second)); - if (nc == -1) - nc = check_compose(toupper(second), toupper(first)); - recurse = 0; - } - return nc; -} - - /* * Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of ASCII * codes. Returns number of bytes used or zero to drop the message @@ -2171,6 +2207,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, int r, i, code; unsigned char *p = output; static int alt_state = 0; + static int alt_sum = 0; HKL kbd_layout = GetKeyboardLayout(0); @@ -2183,6 +2220,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, memset(keystate, 0, sizeof(keystate)); else { #if 0 +#define SHOW_TOASCII_RESULT { /* Tell us all about key events */ static BYTE oldstate[256]; static int first = 1; @@ -2791,19 +2829,38 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, *p++ = 0; return -2; } + + if (left_alt && wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9) + alt_sum = alt_sum * 10 + wParam - VK_NUMPAD0; + else + alt_sum = 0; } /* Okay we've done everything interesting; let windows deal with * the boring stuff */ { - BOOL capsOn = keystate[VK_CAPITAL] != 0; - - /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ - if (cfg.xlat_capslockcyr) - keystate[VK_CAPITAL] = 0; - r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout); +#ifdef SHOW_TOASCII_RESULT + if (r == 1 && !key_down) { + if (alt_sum) { + if (utf || dbcs_screenfont) + debug((", (U+%04x)", alt_sum)); + else + debug((", LCH(%d)", alt_sum)); + } else { + debug((", ACH(%d)", keys[0])); + } + } else if (r > 0) { + int r1; + debug((", ASC(")); + for (r1 = 0; r1 < r; r1++) { + debug(("%s%d", r1 ? "," : "", keys[r1])); + } + debug((")")); + } +#endif if (r > 0) { + WCHAR keybuf; p = output; for (i = 0; i < r; i++) { unsigned char ch = (unsigned char) keys[i]; @@ -2821,20 +2878,30 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, MessageBeep(MB_ICONHAND); return 0; } - *p++ = xlat_kbd2tty((unsigned char) nc); - return p - output; + keybuf = nc; + luni_send(&keybuf, 1); + continue; } compose_state = 0; - if (left_alt && key_down) - *p++ = '\033'; - if (!key_down) - *p++ = ch; - else { - if (capsOn) - ch = xlat_latkbd2win(ch); - *p++ = xlat_kbd2tty(ch); + if (!key_down) { + if (alt_sum) { + if (utf || dbcs_screenfont) { + keybuf = alt_sum; + luni_send(&keybuf, 1); + } else { + ch = (char) alt_sum; + ldisc_send(&ch, 1); + } + alt_sum = 0; + } else + lpage_send(kbd_codepage, &ch, 1); + } else { + static char cbuf[] = "\033 "; + cbuf[1] = ch; + lpage_send(kbd_codepage, cbuf + !left_alt, + 1 + !!left_alt); } } @@ -2846,6 +2913,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* If we're definitly not building up an ALT-54321 then clear it */ if (!left_alt) keys[0] = 0; + /* If we will be using alt_sum fix the 256s */ + else if (keys[0] && (utf || dbcs_screenfont)) + keys[0] = 10; } /* ALT alone may or may not want to bring up the System menu */ @@ -2976,7 +3046,7 @@ void palette_reset(void) } } -void write_clip(void *data, int len, int must_deselect) +void write_aclip(char *data, int len, int must_deselect) { HGLOBAL clipdata; void *lock; @@ -3005,33 +3075,100 @@ void write_clip(void *data, int len, int must_deselect) SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0); } -void get_clip(void **p, int *len) +/* + * Note: unlike write_aclip() this will not append a nul. + */ +void write_clip(wchar_t * data, int len, int must_deselect) +{ + HGLOBAL clipdata; + HGLOBAL clipdata2; + int len2; + void *lock, *lock2; + + len2 = WideCharToMultiByte(CP_ACP, 0, data, len, 0, 0, NULL, NULL); + + clipdata = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, + len * sizeof(wchar_t)); + clipdata2 = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, len2); + + if (!clipdata || !clipdata2) { + if (clipdata) + GlobalFree(clipdata); + if (clipdata2) + GlobalFree(clipdata2); + return; + } + if (!(lock = GlobalLock(clipdata))) + return; + if (!(lock2 = GlobalLock(clipdata2))) + return; + + memcpy(lock, data, len * sizeof(wchar_t)); + WideCharToMultiByte(CP_ACP, 0, data, len, lock2, len2, NULL, NULL); + + GlobalUnlock(clipdata); + GlobalUnlock(clipdata2); + + if (!must_deselect) + SendMessage(hwnd, WM_IGNORE_CLIP, TRUE, 0); + + if (OpenClipboard(hwnd)) { + EmptyClipboard(); + SetClipboardData(CF_UNICODETEXT, clipdata); + SetClipboardData(CF_TEXT, clipdata2); + CloseClipboard(); + } else { + GlobalFree(clipdata); + GlobalFree(clipdata2); + } + + if (!must_deselect) + SendMessage(hwnd, WM_IGNORE_CLIP, FALSE, 0); +} + +void get_clip(wchar_t ** p, int *len) { static HGLOBAL clipdata = NULL; + static wchar_t *converted = 0; + wchar_t *p2; + if (converted) { + sfree(converted); + converted = 0; + } if (!p) { if (clipdata) GlobalUnlock(clipdata); clipdata = NULL; return; - } else { - if (OpenClipboard(NULL)) { - clipdata = GetClipboardData(CF_TEXT); + } else if (OpenClipboard(NULL)) { + if (clipdata = GetClipboardData(CF_UNICODETEXT)) { CloseClipboard(); - if (clipdata) { - *p = GlobalLock(clipdata); - if (*p) { - *len = strlen(*p); - return; - } + *p = GlobalLock(clipdata); + if (*p) { + for (p2 = *p; *p2; p2++); + *len = p2 - *p; + return; } - } + } else if (clipdata = GetClipboardData(CF_TEXT)) { + char *s; + int i; + CloseClipboard(); + s = GlobalLock(clipdata); + i = MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, 0, 0); + *p = converted = smalloc(i * sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, converted, i); + *len = i - 1; + return; + } else + CloseClipboard(); } *p = NULL; *len = 0; } +#if 0 /* * Move `lines' lines from position `from' to position `to' in the * window. @@ -3050,6 +3187,7 @@ void optimised_move(int to, int from, int lines) r.bottom = (max + lines) * font_height; ScrollWindow(hwnd, 0, (to - from) * font_height, &r, &r); } +#endif /* * Print a message box and perform a fatal exit. diff --git a/xlat.c b/xlat.c deleted file mode 100644 index c1d9efc1..00000000 --- a/xlat.c +++ /dev/null @@ -1,233 +0,0 @@ -#include -#include -#include "putty.h" - -static unsigned char win2koi[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, - 160, 161, 162, 163, 164, 189, 166, 167, 179, 169, 180, 171, 172, 173, - 174, 183, - 176, 177, 182, 166, 173, 181, 182, 183, 163, 185, 164, 187, 188, 189, - 190, 167, - 225, 226, 247, 231, 228, 229, 246, 250, 233, 234, 235, 236, 237, 238, - 239, 240, - 242, 243, 244, 245, 230, 232, 227, 254, 251, 253, 255, 249, 248, 252, - 224, 241, - 193, 194, 215, 199, 196, 197, 214, 218, 201, 202, 203, 204, 205, 206, - 207, 208, - 210, 211, 212, 213, 198, 200, 195, 222, 219, 221, 223, 217, 216, 220, - 192, 209 -}; - -static unsigned char koi2win[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, - 160, 161, 162, 184, 186, 165, 179, 191, 168, 169, 170, 171, 172, 180, - 174, 175, - 176, 177, 178, 168, 170, 181, 178, 175, 184, 185, 186, 187, 188, 165, - 190, 191, - 254, 224, 225, 246, 228, 229, 244, 227, 245, 232, 233, 234, 235, 236, - 237, 238, - 239, 255, 240, 241, 242, 243, 230, 226, 252, 251, 231, 248, 253, 249, - 247, 250, - 222, 192, 193, 214, 196, 197, 212, 195, 213, 200, 201, 202, 203, 204, - 205, 206, - 207, 223, 208, 209, 210, 211, 198, 194, 220, 219, 199, 216, 221, 217, - 215, 218 -}; - -static unsigned char xlatWIN1250toISO88592[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, - 128, 129, 39, 131, 34, 46, 124, 124, 136, 47, 169, 60, 166, 171, 174, - 172, - 144, 96, 39, 34, 34, 42, 45, 45, 152, 84, 185, 62, 182, 187, 190, 188, - 160, 183, 162, 163, 164, 161, 124, 167, 168, 99, 170, 34, 39, 173, 82, - 175, - 176, 63, 178, 179, 180, 117, 182, 255, 184, 177, 186, 34, 165, 189, - 181, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255 -}; - -static unsigned char xlatISO88592toWIN1250[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, - 160, 165, 162, 163, 164, 188, 140, 167, 168, 138, 170, 141, 143, 173, - 142, 175, - 176, 185, 178, 179, 180, 190, 156, 161, 184, 154, 186, 157, 159, 189, - 158, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255 -}; - -static unsigned char xlatISO88592toCP852[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, - 242, 32, 34, 32, 34, 46, 43, 35, 32, 47, 138, 60, 151, 141, 166, 141, - 032, 34, 34, 34, 34, 254, 45, 45, 32, 126, 154, 62, 152, 157, 167, 171, - 255, 164, 244, 157, 207, 149, 151, 245, 249, 230, 184, 155, 141, 240, - 166, 189, - 248, 165, 247, 136, 239, 150, 152, 243, 242, 231, 173, 156, 171, 241, - 167, 190, - 232, 181, 182, 198, 142, 145, 143, 128, 172, 144, 168, 211, 183, 214, - 215, 210, - 209, 227, 213, 224, 226, 138, 153, 158, 252, 222, 233, 235, 154, 237, - 221, 225, - 234, 160, 131, 199, 132, 146, 134, 135, 159, 130, 169, 137, 216, 161, - 140, 212, - 208, 228, 229, 162, 147, 139, 148, 246, 253, 133, 163, 251, 129, 236, - 238, 250, -}; - -static unsigned char xlatCP852toISO88592[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, - 199, 252, 233, 226, 228, 249, 230, 231, 179, 235, 138, 245, 238, 141, - 196, 198, - 201, 197, 229, 244, 246, 165, 181, 140, 156, 214, 154, 171, 187, 157, - 215, 232, - 225, 237, 243, 250, 161, 177, 142, 158, 202, 234, 170, 159, 200, 186, - 174, 175, - 176, 177, 178, 179, 180, 193, 194, 204, 170, 185, 186, 187, 188, 175, - 191, 191, - 192, 193, 194, 195, 196, 197, 195, 227, 200, 201, 202, 203, 204, 205, - 206, 164, - 240, 208, 207, 203, 239, 210, 205, 206, 236, 217, 218, 219, 220, 222, - 217, 223, - 211, 223, 212, 209, 241, 242, 169, 185, 192, 218, 224, 219, 253, 221, - 254, 180, - 173, 189, 128, 183, 162, 167, 247, 178, 176, 168, 255, 251, 216, 248, - 149, 160, -}; - -unsigned char xlat_kbd2tty(unsigned char c) -{ - if (cfg.xlat_enablekoiwin) - return win2koi[c]; - else if (cfg.xlat_88592w1250 || cfg.xlat_88592cp852) - return xlatWIN1250toISO88592[c]; - return c; -} - -unsigned char xlat_tty2scr(unsigned char c) -{ - if (cfg.xlat_enablekoiwin) - return koi2win[c]; - else if (cfg.xlat_88592w1250) - return xlatISO88592toWIN1250[c]; - else if (cfg.xlat_88592cp852) - return xlatISO88592toCP852[c]; - return c; -} - - -static unsigned char latkbd2_win[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 221, 35, 36, 37, 38, 253, 40, 41, 42, 178, 225, 186, 254, 46, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 198, 230, 193, 179, 222, 44, - 64, 212, 200, 209, 194, 211, 192, 207, 208, 216, 206, 203, 196, 220, - 210, 217, - 199, 201, 202, 219, 197, 195, 204, 214, 215, 205, 223, 245, 191, 250, - 94, 170, - 96, 244, 232, 241, 226, 243, 224, 239, 240, 248, 238, 235, 228, 252, - 242, 249, - 231, 233, 234, 251, 229, 227, 236, 246, 247, 237, 255, 213, 175, 218, - 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255 -}; - -unsigned char xlat_latkbd2win(unsigned char c) -{ - if (cfg.xlat_capslockcyr) - return latkbd2_win[c]; - return c; -} -- 2.11.0