Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Tatham <anakin@pobox.com>2001-05-10 12:34:20 +0400
committerSimon Tatham <anakin@pobox.com>2001-05-10 12:34:20 +0400
commit26f1085038d7cd9a63808a33ec6feb695b68734a (patch)
tree19ec785841a765f94967b2b4aa3521f486280e5a
parente001f1533e0e8b900e69924af9509d8733d94259 (diff)
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. [originally from svn r1110]
-rw-r--r--Makefile2
-rw-r--r--ldisc.c4
-rw-r--r--putty.h118
-rw-r--r--settings.c11
-rw-r--r--terminal.c1090
-rw-r--r--unicode.c982
-rw-r--r--wcwidth.c190
-rw-r--r--windlg.c84
-rw-r--r--window.c862
-rw-r--r--xlat.c233
10 files changed, 2614 insertions, 962 deletions
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, "<U+%04x>", (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 <windows.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <time.h>
+#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"
+ * <http://www.UNIX-systems.org/online.html>
+ *
+ * Markus Kuhn -- 2000-02-08 -- public domain
+ */
+
+#include <wchar.h>
+
+/* 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 <windows.h>
-#include <stdio.h>
-#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;
-}