]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unicode.c
Three more patches from RDB: one to make Atomica work right, one to
[PuTTY.git] / unicode.c
1 #include <windows.h>
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <ctype.h>
6
7 #include <time.h>
8 #include "putty.h"
9 #include "misc.h"
10
11 void init_ucs_tables(void);
12 void lpage_send(int codepage, char *buf, int len);
13 void luni_send(wchar_t * widebuf, int len);
14
15 static void get_unitab(int codepage, wchar_t * unitab, int ftype);
16
17 /* Character conversion arrays; they are usually taken from windows,
18  * the xterm one has the four scanlines that have no unicode 2.0
19  * equivalents mapped to their unicode 3.0 locations.
20  */
21 static char **uni_tbl;
22
23 static WCHAR unitab_xterm_std[32] = {
24     0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
25     0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
26     0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
27     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020
28 };
29
30 /*
31  * If the codepage is non-zero it's a window codepage, zero means use a
32  * local codepage. The name is always converted to the first of any
33  * duplicate definitions.
34  */
35
36 static wchar_t iso_8859_10[] = {
37     0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7,
38     0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A,
39     0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7,
40     0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2014, 0x016B, 0x014B,
41     0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
42     0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF,
43     0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168,
44     0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
45     0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
46     0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF,
47     0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169,
48     0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138
49 };
50
51 static wchar_t iso_8859_11[] = {
52     0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07,
53     0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F,
54     0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17,
55     0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F,
56     0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27,
57     0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F,
58     0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37,
59     0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F,
60     0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47,
61     0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F,
62     0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57,
63     0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
64 };
65
66 static wchar_t iso_8859_13[] = {
67     0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7,
68     0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
69     0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7,
70     0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
71     0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
72     0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
73     0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
74     0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
75     0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
76     0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
77     0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
78     0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019
79 };
80
81 static wchar_t iso_8859_14[] = {
82     0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7,
83     0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178,
84     0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56,
85     0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61,
86     0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
87     0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
88     0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A,
89     0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF,
90     0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
91     0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
92     0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B,
93     0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF
94 };
95
96 static wchar_t iso_8859_15[] = {
97     0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20ac, 0x00a5, 0x0160, 0x00a7,
98     0x0161, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
99     0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x017d, 0x00b5, 0x00b6, 0x00b7,
100     0x017e, 0x00b9, 0x00ba, 0x00bb, 0x0152, 0x0153, 0x0178, 0x00bf,
101     0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
102     0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
103     0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
104     0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
105     0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
106     0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
107     0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
108     0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
109 };
110
111 static wchar_t iso_8859_16[] = {
112     0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7,
113     0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B,
114     0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7,
115     0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C,
116     0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7,
117     0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
118     0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A,
119     0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF,
120     0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7,
121     0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
122     0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B,
123     0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF
124 };
125
126 static wchar_t roman8[] = {
127     0x00A0, 0x00C0, 0x00C2, 0x00C8, 0x00CA, 0x00CB, 0x00CE, 0x00CF,
128     0x00B4, 0x02CB, 0x02C6, 0x00A8, 0x02DC, 0x00D9, 0x00DB, 0x20A4,
129     0x00AF, 0x00DD, 0x00FD, 0x00B0, 0x00C7, 0x00E7, 0x00D1, 0x00F1,
130     0x00A1, 0x00BF, 0x00A4, 0x00A3, 0x00A5, 0x00A7, 0x0192, 0x00A2,
131     0x00E2, 0x00EA, 0x00F4, 0x00FB, 0x00E1, 0x00E9, 0x00F3, 0x00FA,
132     0x00E0, 0x00E8, 0x00F2, 0x00F9, 0x00E4, 0x00EB, 0x00F6, 0x00FC,
133     0x00C5, 0x00EE, 0x00D8, 0x00C6, 0x00E5, 0x00ED, 0x00F8, 0x00E6,
134     0x00C4, 0x00EC, 0x00D6, 0x00DC, 0x00C9, 0x00EF, 0x00DF, 0x00D4,
135     0x00C1, 0x00C3, 0x00E3, 0x00D0, 0x00F0, 0x00CD, 0x00CC, 0x00D3,
136     0x00D2, 0x00D5, 0x00F5, 0x0160, 0x0161, 0x00DA, 0x0178, 0x00FF,
137     0x00DE, 0x00FE, 0x00B7, 0x00B5, 0x00B6, 0x00BE, 0x2014, 0x00BC,
138     0x00BD, 0x00AA, 0x00BA, 0x00AB, 0x25A0, 0x00BB, 0x00B1, 0xFFFD
139 };
140
141 static wchar_t koi8_u[] = {
142     0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
143     0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
144     0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2022, 0x221A, 0x2248,
145     0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7,
146     0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457,
147     0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E,
148     0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407,
149     0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9,
150     0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
151     0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
152     0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
153     0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
154     0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
155     0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
156     0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
157     0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A
158 };
159
160 static wchar_t vscii[] = {
161     0x0000, 0x0001, 0x1EB2, 0x0003, 0x0004, 0x1EB4, 0x1EAA, 0x0007,
162     0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
163     0x0010, 0x0011, 0x0012, 0x0013, 0x1EF6, 0x0015, 0x0016, 0x0017,
164     0x0018, 0x1EF8, 0x001a, 0x001b, 0x001c, 0x001d, 0x1EF4, 0x001f,
165     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
166     0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
167     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
168     0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
169     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
170     0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
171     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
172     0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
173     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
174     0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
175     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
176     0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007f,
177     0x1EA0, 0x1EAE, 0x1EB0, 0x1EB6, 0x1EA4, 0x1EA6, 0x1EA8, 0x1EAC,
178     0x1EBC, 0x1EB8, 0x1EBE, 0x1EC0, 0x1EC2, 0x1EC4, 0x1EC6, 0x1ED0,
179     0x1ED2, 0x1ED4, 0x1ED6, 0x1ED8, 0x1EE2, 0x1EDA, 0x1EDC, 0x1EDE,
180     0x1ECA, 0x1ECE, 0x1ECC, 0x1EC8, 0x1EE6, 0x0168, 0x1EE4, 0x1EF2,
181     0x00D5, 0x1EAF, 0x1EB1, 0x1EB7, 0x1EA5, 0x1EA7, 0x1EA8, 0x1EAD,
182     0x1EBD, 0x1EB9, 0x1EBF, 0x1EC1, 0x1EC3, 0x1EC5, 0x1EC7, 0x1ED1,
183     0x1ED3, 0x1ED5, 0x1ED7, 0x1EE0, 0x01A0, 0x1ED9, 0x1EDD, 0x1EDF,
184     0x1ECB, 0x1EF0, 0x1EE8, 0x1EEA, 0x1EEC, 0x01A1, 0x1EDB, 0x01AF,
185     0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x1EA2, 0x0102, 0x1EB3, 0x1EB5,
186     0x00C8, 0x00C9, 0x00CA, 0x1EBA, 0x00CC, 0x00CD, 0x0128, 0x1EF3,
187     0x0110, 0x1EE9, 0x00D2, 0x00D3, 0x00D4, 0x1EA1, 0x1EF7, 0x1EEB,
188     0x1EED, 0x00D9, 0x00DA, 0x1EF9, 0x1EF5, 0x00DD, 0x1EE1, 0x01B0,
189     0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x1EA3, 0x0103, 0x1EEF, 0x1EAB,
190     0x00E8, 0x00E9, 0x00EA, 0x1EBB, 0x00EC, 0x00ED, 0x0129, 0x1EC9,
191     0x0111, 0x1EF1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x1ECF, 0x1ECD,
192     0x1EE5, 0x00F9, 0x00FA, 0x0169, 0x1EE7, 0x00FD, 0x1EE3, 0x1EEE
193 };
194
195 static wchar_t dec_mcs[] = {
196     0x00A0, 0x00A1, 0x00A2, 0x00A3, 0xFFFD, 0x00A5, 0xFFFD, 0x00A7,
197     0x00A4, 0x00A9, 0x00AA, 0x00AB, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
198     0x00B0, 0x00B1, 0x00B2, 0x00B3, 0xFFFD, 0x00B5, 0x00B6, 0x00B7,
199     0xFFFD, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0xFFFD, 0x00BF,
200     0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
201     0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
202     0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0152,
203     0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0178, 0xFFFD, 0x00DF,
204     0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
205     0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
206     0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0153,
207     0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FF, 0xFFFD, 0xFFFD
208 };
209
210 struct cp_list_item {
211     char *name;
212     int codepage;
213     int cp_size;
214     wchar_t *cp_table;
215 };
216
217 static struct cp_list_item cp_list[] = {
218     {"ISO-8859-1:1987", 28591},
219     {"ISO-8859-2:1987", 28592},
220     {"ISO-8859-3:1988", 28593},
221     {"ISO-8859-4:1988", 28594},
222     {"ISO-8859-5:1988", 28595},
223     {"ISO-8859-6:1987", 28596},
224     {"ISO-8859-7:1987", 28597},
225     {"ISO-8859-8:1988", 28598},
226     {"ISO-8859-9:1989", 28599},
227     {"ISO-8859-10:1993", 0, 96, iso_8859_10},
228     {"ISO-8859-11:1997", 0, 96, iso_8859_11},
229     {"ISO-8859-13:1998", 0, 96, iso_8859_13},
230     {"ISO-8859-14:1998", 0, 96, iso_8859_14},
231     {"ISO-8859-15:1998", 0, 96, iso_8859_15},
232     {"ISO-8859-16:2001", 0, 96, iso_8859_16},
233
234     {"UTF-8", CP_UTF8},
235
236     {"KOI8-U", 0, 128, koi8_u},
237     {"KOI8-R", 20866},
238     {"HP-ROMAN8", 0, 96, roman8},
239     {"VSCII", 0, 256, vscii},
240     {"DEC-MCS", 0, 96, dec_mcs},
241
242     {"Win1250 (Central European)", 1250},
243     {"Win1251 (Cyrillic)", 1251},
244     {"Win1252 (Western)", 1252},
245     {"Win1253 (Greek)", 1253},
246     {"Win1254 (Turkish)", 1254},
247     {"Win1255 (Hebrew)", 1255},
248     {"Win1256 (Arabic)", 1256},
249     {"Win1257 (Baltic)", 1257},
250     {"Win1258 (Vietnamese)", 1258},
251
252     {"Win1258 (Vietnamese)", 1258},
253
254     {"CP437", 437},
255     {"CP819", 28591},
256     {"CP878", 20866},
257
258     {"Use font encoding", -1},
259
260     {0, 0}
261 };
262
263 static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr);
264
265 void init_ucs_tables(void)
266 {
267     int i, j;
268     int used_dtf = 0;
269     char tbuf[256];
270
271     for (i = 0; i < 256; i++)
272         tbuf[i] = i;
273
274     /* Decide on the Line and Font codepages */
275     line_codepage = decode_codepage(cfg.line_codepage);
276
277     if (font_codepage <= 0) { 
278         font_codepage=0; 
279         dbcs_screenfont=0; 
280     }
281
282     if (cfg.vtmode == VT_OEMONLY) {
283         font_codepage = 437;
284         dbcs_screenfont = 0;
285         if (line_codepage <= 0)
286             line_codepage = GetACP();
287     } else if (line_codepage <= 0)
288         line_codepage = font_codepage;
289
290     /* Collect screen font ucs table */
291     if (dbcs_screenfont || font_codepage == 0) {
292         get_unitab(font_codepage, unitab_font, 2);
293         for (i = 128; i < 256; i++)
294             unitab_font[i] = (WCHAR) (ATTR_ACP + i);
295     } else {
296         get_unitab(font_codepage, unitab_font, 1);
297
298         /* CP437 fonts are often broken ... */
299         if (font_codepage == 437)
300             unitab_font[0] = unitab_font[255] = 0xFFFF;
301     }
302     if (cfg.vtmode == VT_XWINDOWS)
303         memcpy(unitab_font + 1, unitab_xterm_std,
304                sizeof(unitab_xterm_std));
305
306     /* Collect OEMCP ucs table */
307     get_unitab(CP_OEMCP, unitab_oemcp, 1);
308
309     /* Collect CP437 ucs table for SCO acs */
310     if (cfg.vtmode == VT_OEMANSI || cfg.vtmode == VT_XWINDOWS)
311         memcpy(unitab_scoacs, unitab_oemcp, sizeof(unitab_scoacs));
312     else
313         get_unitab(437, unitab_scoacs, 1);
314
315     /* Collect line set ucs table */
316     if (line_codepage == font_codepage &&
317         (dbcs_screenfont || cfg.vtmode == VT_POORMAN || font_codepage==0)) {
318
319         /* For DBCS and POOR fonts force direct to font */
320         used_dtf = 1;
321         for (i = 0; i < 32; i++)
322             unitab_line[i] = (WCHAR) i;
323         for (i = 32; i < 256; i++)
324             unitab_line[i] = (WCHAR) (ATTR_ACP + i);
325         unitab_line[127] = (WCHAR) 127;
326     } else {
327         get_unitab(line_codepage, unitab_line, 0);
328     }
329
330 #if 0
331     debug(
332           ("Line cp%d, Font cp%d%s\n", line_codepage, font_codepage,
333            dbcs_screenfont ? " DBCS" : ""));
334
335     for (i = 0; i < 256; i += 16) {
336         for (j = 0; j < 16; j++) {
337             debug(("%04x%s", unitab_line[i + j], j == 15 ? "" : ","));
338         }
339         debug(("\n"));
340     }
341 #endif
342
343     /* VT100 graphics - NB: Broken for non-ascii CP's */
344     memcpy(unitab_xterm, unitab_line, sizeof(unitab_xterm));
345     memcpy(unitab_xterm + '`', unitab_xterm_std, sizeof(unitab_xterm_std));
346     unitab_xterm['_'] = ' ';
347
348     /* Generate UCS ->line page table. */
349     if (uni_tbl) {
350         for (i = 0; i < 256; i++)
351             if (uni_tbl[i])
352                 sfree(uni_tbl[i]);
353         sfree(uni_tbl);
354         uni_tbl = 0;
355     }
356     if (!used_dtf) {
357         for (i = 0; i < 256; i++) {
358             if (DIRECT_CHAR(unitab_line[i]))
359                 continue;
360             if (DIRECT_FONT(unitab_line[i]))
361                 continue;
362             if (!uni_tbl) {
363                 uni_tbl = smalloc(256 * sizeof(char *));
364                 memset(uni_tbl, 0, 256 * sizeof(char *));
365             }
366             j = ((unitab_line[i] >> 8) & 0xFF);
367             if (!uni_tbl[j]) {
368                 uni_tbl[j] = smalloc(256 * sizeof(char));
369                 memset(uni_tbl[j], 0, 256 * sizeof(char));
370             }
371             uni_tbl[j][unitab_line[i] & 0xFF] = i;
372         }
373     }
374
375     /* Find the line control characters. */
376     for (i = 0; i < 256; i++)
377         if (unitab_line[i] < ' '
378             || (unitab_line[i] >= 0x7F && unitab_line[i] < 0xA0))
379             unitab_ctrl[i] = i;
380         else
381             unitab_ctrl[i] = 0xFF;
382
383     /* Generate line->screen direct conversion links. */
384     if (cfg.vtmode == VT_OEMANSI || cfg.vtmode == VT_XWINDOWS)
385         link_font(unitab_scoacs, unitab_oemcp, ATTR_OEMCP);
386
387     link_font(unitab_line, unitab_font, ATTR_ACP);
388     link_font(unitab_scoacs, unitab_font, ATTR_ACP);
389     link_font(unitab_xterm, unitab_font, ATTR_ACP);
390
391     if (cfg.vtmode == VT_OEMANSI || cfg.vtmode == VT_XWINDOWS) {
392         link_font(unitab_line, unitab_oemcp, ATTR_OEMCP);
393         link_font(unitab_xterm, unitab_oemcp, ATTR_OEMCP);
394     }
395
396     if (dbcs_screenfont && font_codepage != line_codepage) {
397         /* F***ing Microsoft fonts, Japanese and Korean codepage fonts
398          * have a currency symbol at 0x5C but their unicode value is 
399          * still given as U+005C not the correct U+00A5. */
400         unitab_line['\\'] = ATTR_OEMCP + '\\';
401     }
402
403     /* Last chance, if !unicode then try poorman links. */
404     if (cfg.vtmode != VT_UNICODE) {
405         static char poorman_scoacs[] = 
406             "CueaaaaceeeiiiAAE**ooouuyOUc$YPsaiounNao?++**!<>###||||++||++++++--|-+||++--|-+----++++++++##||#aBTPEsyt******EN=+><++-=... n2* ";
407         static char poorman_latin1[] =
408             " !cL.Y|S\"Ca<--R~o+23'u|.,1o>///?AAAAAAACEEEEIIIIDNOOOOOxOUUUUYPBaaaaaaaceeeeiiiionooooo/ouuuuypy";
409         static char poorman_vt100[] = "*#****o~**+++++-----++++|****L.";
410
411         for (i = 160; i < 256; i++)
412             if (!DIRECT_FONT(unitab_line[i]) &&
413                 unitab_line[i] >= 160 && unitab_line[i] < 256)
414                 unitab_line[i] = (WCHAR) (ATTR_ACP
415                                           + poorman_latin1[unitab_line[i] -
416                                                            160]);
417         for (i = 96; i < 127; i++)
418             if (!DIRECT_FONT(unitab_xterm[i]))
419                 unitab_xterm[i] =
420                     (WCHAR) (ATTR_ACP + poorman_vt100[i - 96]);
421         for(i=128;i<256;i++) 
422             if (!DIRECT_FONT(unitab_scoacs[i]))
423                 unitab_scoacs[i] = 
424                     (WCHAR) (ATTR_ACP + poorman_scoacs[i - 128]);
425     }
426 }
427
428 static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr)
429 {
430     int font_index, line_index, i;
431     for (line_index = 0; line_index < 256; line_index++) {
432         if (DIRECT_FONT(line_tbl[line_index]))
433             continue;
434         for(i = 0; i < 256; i++) {
435             font_index = ((32 + i) & 0xFF);
436             if (line_tbl[line_index] == font_tbl[font_index]) {
437                 line_tbl[line_index] = (WCHAR) (attr + font_index);
438                 break;
439             }
440         }
441     }
442 }
443
444 void lpage_send(int codepage, char *buf, int len)
445 {
446     static wchar_t *widebuffer = 0;
447     static int widesize = 0;
448     int wclen;
449
450     if (codepage < 0) {
451         ldisc_send(buf, len);
452         return;
453     }
454
455     if (len > widesize) {
456         sfree(widebuffer);
457         widebuffer = smalloc(len * 2 * sizeof(wchar_t));
458         widesize = len * 2;
459     }
460
461     wclen =
462         MultiByteToWideChar(codepage, 0, buf, len, widebuffer, widesize);
463     luni_send(widebuffer, wclen);
464 }
465
466 void luni_send(wchar_t * widebuf, int len)
467 {
468     static char *linebuffer = 0;
469     static int linesize = 0;
470     int ratio = (in_utf)?3:1;
471     int i;
472     char *p;
473
474     if (len * ratio > linesize) {
475         sfree(linebuffer);
476         linebuffer = smalloc(len * ratio * 2 * sizeof(wchar_t));
477         linesize = len * ratio * 2;
478     }
479
480     if (in_utf) {
481         /* UTF is a simple algorithm */
482         for (p = linebuffer, i = 0; i < len; i++) {
483             wchar_t ch = widebuf[i];
484             /* Windows wchar_t is UTF-16 */
485             if ((ch&0xF800) == 0xD800) ch = '.';
486
487             if (ch < 0x80) {
488                 *p++ = (char) (ch);
489             } else if (ch < 0x800) {
490                 *p++ = (0xC0 | (ch >> 6));
491                 *p++ = (0x80 | (ch & 0x3F));
492             } else {
493                 *p++ = (0xE0 | (ch >> 12));
494                 *p++ = (0x80 | ((ch >> 6) & 0x3F));
495                 *p++ = (0x80 | (ch & 0x3F));
496             }
497         }
498     } else if (!uni_tbl) {
499         int rv;
500         rv = WideCharToMultiByte(line_codepage, 0, widebuf, len,
501                                  linebuffer, linesize, NULL, NULL);
502         if (rv >= 0)
503             p = linebuffer + rv;
504         else
505             p = linebuffer;
506     } else {
507         /* Others are a lookup in an array */
508         for (p = linebuffer, i = 0; i < len; i++) {
509             wchar_t ch = widebuf[i];
510             int by;
511             char *p1;
512             if (uni_tbl && (p1 = uni_tbl[(ch >> 8) & 0xFF])
513                 && (by = p1[ch & 0xFF]))
514                 *p++ = by;
515             else if (ch < 0x80)
516                 *p++ = (char) ch;
517 #if 1
518             else
519                 *p++ = '.';
520 #endif
521         }
522     }
523     if (p > linebuffer)
524         ldisc_send(linebuffer, p - linebuffer);
525 }
526
527 int check_compose(int first, int second)
528 {
529
530     static struct {
531         char first, second;
532         wchar_t composed;
533     } composetbl[] = {
534         {
535         0x2b, 0x2b, 0x0023}, {
536         0x41, 0x41, 0x0040}, {
537         0x28, 0x28, 0x005b}, {
538         0x2f, 0x2f, 0x005c}, {
539         0x29, 0x29, 0x005d}, {
540         0x28, 0x2d, 0x007b}, {
541         0x2d, 0x29, 0x007d}, {
542         0x2f, 0x5e, 0x007c}, {
543         0x21, 0x21, 0x00a1}, {
544         0x43, 0x2f, 0x00a2}, {
545         0x43, 0x7c, 0x00a2}, {
546         0x4c, 0x2d, 0x00a3}, {
547         0x4c, 0x3d, 0x20a4}, {
548         0x58, 0x4f, 0x00a4}, {
549         0x58, 0x30, 0x00a4}, {
550         0x59, 0x2d, 0x00a5}, {
551         0x59, 0x3d, 0x00a5}, {
552         0x7c, 0x7c, 0x00a6}, {
553         0x53, 0x4f, 0x00a7}, {
554         0x53, 0x21, 0x00a7}, {
555         0x53, 0x30, 0x00a7}, {
556         0x22, 0x22, 0x00a8}, {
557         0x43, 0x4f, 0x00a9}, {
558         0x43, 0x30, 0x00a9}, {
559         0x41, 0x5f, 0x00aa}, {
560         0x3c, 0x3c, 0x00ab}, {
561         0x2c, 0x2d, 0x00ac}, {
562         0x2d, 0x2d, 0x00ad}, {
563         0x52, 0x4f, 0x00ae}, {
564         0x2d, 0x5e, 0x00af}, {
565         0x30, 0x5e, 0x00b0}, {
566         0x2b, 0x2d, 0x00b1}, {
567         0x32, 0x5e, 0x00b2}, {
568         0x33, 0x5e, 0x00b3}, {
569         0x27, 0x27, 0x00b4}, {
570         0x2f, 0x55, 0x00b5}, {
571         0x50, 0x21, 0x00b6}, {
572         0x2e, 0x5e, 0x00b7}, {
573         0x2c, 0x2c, 0x00b8}, {
574         0x31, 0x5e, 0x00b9}, {
575         0x4f, 0x5f, 0x00ba}, {
576         0x3e, 0x3e, 0x00bb}, {
577         0x31, 0x34, 0x00bc}, {
578         0x31, 0x32, 0x00bd}, {
579         0x33, 0x34, 0x00be}, {
580         0x3f, 0x3f, 0x00bf}, {
581         0x60, 0x41, 0x00c0}, {
582         0x27, 0x41, 0x00c1}, {
583         0x5e, 0x41, 0x00c2}, {
584         0x7e, 0x41, 0x00c3}, {
585         0x22, 0x41, 0x00c4}, {
586         0x2a, 0x41, 0x00c5}, {
587         0x41, 0x45, 0x00c6}, {
588         0x2c, 0x43, 0x00c7}, {
589         0x60, 0x45, 0x00c8}, {
590         0x27, 0x45, 0x00c9}, {
591         0x5e, 0x45, 0x00ca}, {
592         0x22, 0x45, 0x00cb}, {
593         0x60, 0x49, 0x00cc}, {
594         0x27, 0x49, 0x00cd}, {
595         0x5e, 0x49, 0x00ce}, {
596         0x22, 0x49, 0x00cf}, {
597         0x2d, 0x44, 0x00d0}, {
598         0x7e, 0x4e, 0x00d1}, {
599         0x60, 0x4f, 0x00d2}, {
600         0x27, 0x4f, 0x00d3}, {
601         0x5e, 0x4f, 0x00d4}, {
602         0x7e, 0x4f, 0x00d5}, {
603         0x22, 0x4f, 0x00d6}, {
604         0x58, 0x58, 0x00d7}, {
605         0x2f, 0x4f, 0x00d8}, {
606         0x60, 0x55, 0x00d9}, {
607         0x27, 0x55, 0x00da}, {
608         0x5e, 0x55, 0x00db}, {
609         0x22, 0x55, 0x00dc}, {
610         0x27, 0x59, 0x00dd}, {
611         0x48, 0x54, 0x00de}, {
612         0x73, 0x73, 0x00df}, {
613         0x60, 0x61, 0x00e0}, {
614         0x27, 0x61, 0x00e1}, {
615         0x5e, 0x61, 0x00e2}, {
616         0x7e, 0x61, 0x00e3}, {
617         0x22, 0x61, 0x00e4}, {
618         0x2a, 0x61, 0x00e5}, {
619         0x61, 0x65, 0x00e6}, {
620         0x2c, 0x63, 0x00e7}, {
621         0x60, 0x65, 0x00e8}, {
622         0x27, 0x65, 0x00e9}, {
623         0x5e, 0x65, 0x00ea}, {
624         0x22, 0x65, 0x00eb}, {
625         0x60, 0x69, 0x00ec}, {
626         0x27, 0x69, 0x00ed}, {
627         0x5e, 0x69, 0x00ee}, {
628         0x22, 0x69, 0x00ef}, {
629         0x2d, 0x64, 0x00f0}, {
630         0x7e, 0x6e, 0x00f1}, {
631         0x60, 0x6f, 0x00f2}, {
632         0x27, 0x6f, 0x00f3}, {
633         0x5e, 0x6f, 0x00f4}, {
634         0x7e, 0x6f, 0x00f5}, {
635         0x22, 0x6f, 0x00f6}, {
636         0x3a, 0x2d, 0x00f7}, {
637         0x6f, 0x2f, 0x00f8}, {
638         0x60, 0x75, 0x00f9}, {
639         0x27, 0x75, 0x00fa}, {
640         0x5e, 0x75, 0x00fb}, {
641         0x22, 0x75, 0x00fc}, {
642         0x27, 0x79, 0x00fd}, {
643         0x68, 0x74, 0x00fe}, {
644         0x22, 0x79, 0x00ff},
645             /* Unicode extras. */
646         {
647         0x6f, 0x65, 0x0153}, {
648         0x4f, 0x45, 0x0152},
649             /* Compose pairs from UCS */
650         {
651         0x41, 0x2D, 0x0100}, {
652         0x61, 0x2D, 0x0101}, {
653         0x43, 0x27, 0x0106}, {
654         0x63, 0x27, 0x0107}, {
655         0x43, 0x5E, 0x0108}, {
656         0x63, 0x5E, 0x0109}, {
657         0x45, 0x2D, 0x0112}, {
658         0x65, 0x2D, 0x0113}, {
659         0x47, 0x5E, 0x011C}, {
660         0x67, 0x5E, 0x011D}, {
661         0x47, 0x2C, 0x0122}, {
662         0x67, 0x2C, 0x0123}, {
663         0x48, 0x5E, 0x0124}, {
664         0x68, 0x5E, 0x0125}, {
665         0x49, 0x7E, 0x0128}, {
666         0x69, 0x7E, 0x0129}, {
667         0x49, 0x2D, 0x012A}, {
668         0x69, 0x2D, 0x012B}, {
669         0x4A, 0x5E, 0x0134}, {
670         0x6A, 0x5E, 0x0135}, {
671         0x4B, 0x2C, 0x0136}, {
672         0x6B, 0x2C, 0x0137}, {
673         0x4C, 0x27, 0x0139}, {
674         0x6C, 0x27, 0x013A}, {
675         0x4C, 0x2C, 0x013B}, {
676         0x6C, 0x2C, 0x013C}, {
677         0x4E, 0x27, 0x0143}, {
678         0x6E, 0x27, 0x0144}, {
679         0x4E, 0x2C, 0x0145}, {
680         0x6E, 0x2C, 0x0146}, {
681         0x4F, 0x2D, 0x014C}, {
682         0x6F, 0x2D, 0x014D}, {
683         0x52, 0x27, 0x0154}, {
684         0x72, 0x27, 0x0155}, {
685         0x52, 0x2C, 0x0156}, {
686         0x72, 0x2C, 0x0157}, {
687         0x53, 0x27, 0x015A}, {
688         0x73, 0x27, 0x015B}, {
689         0x53, 0x5E, 0x015C}, {
690         0x73, 0x5E, 0x015D}, {
691         0x53, 0x2C, 0x015E}, {
692         0x73, 0x2C, 0x015F}, {
693         0x54, 0x2C, 0x0162}, {
694         0x74, 0x2C, 0x0163}, {
695         0x55, 0x7E, 0x0168}, {
696         0x75, 0x7E, 0x0169}, {
697         0x55, 0x2D, 0x016A}, {
698         0x75, 0x2D, 0x016B}, {
699         0x55, 0x2A, 0x016E}, {
700         0x75, 0x2A, 0x016F}, {
701         0x57, 0x5E, 0x0174}, {
702         0x77, 0x5E, 0x0175}, {
703         0x59, 0x5E, 0x0176}, {
704         0x79, 0x5E, 0x0177}, {
705         0x59, 0x22, 0x0178}, {
706         0x5A, 0x27, 0x0179}, {
707         0x7A, 0x27, 0x017A}, {
708         0x47, 0x27, 0x01F4}, {
709         0x67, 0x27, 0x01F5}, {
710         0x4E, 0x60, 0x01F8}, {
711         0x6E, 0x60, 0x01F9}, {
712         0x45, 0x2C, 0x0228}, {
713         0x65, 0x2C, 0x0229}, {
714         0x59, 0x2D, 0x0232}, {
715         0x79, 0x2D, 0x0233}, {
716         0x44, 0x2C, 0x1E10}, {
717         0x64, 0x2C, 0x1E11}, {
718         0x47, 0x2D, 0x1E20}, {
719         0x67, 0x2D, 0x1E21}, {
720         0x48, 0x22, 0x1E26}, {
721         0x68, 0x22, 0x1E27}, {
722         0x48, 0x2C, 0x1E28}, {
723         0x68, 0x2C, 0x1E29}, {
724         0x4B, 0x27, 0x1E30}, {
725         0x6B, 0x27, 0x1E31}, {
726         0x4D, 0x27, 0x1E3E}, {
727         0x6D, 0x27, 0x1E3F}, {
728         0x50, 0x27, 0x1E54}, {
729         0x70, 0x27, 0x1E55}, {
730         0x56, 0x7E, 0x1E7C}, {
731         0x76, 0x7E, 0x1E7D}, {
732         0x57, 0x60, 0x1E80}, {
733         0x77, 0x60, 0x1E81}, {
734         0x57, 0x27, 0x1E82}, {
735         0x77, 0x27, 0x1E83}, {
736         0x57, 0x22, 0x1E84}, {
737         0x77, 0x22, 0x1E85}, {
738         0x58, 0x22, 0x1E8C}, {
739         0x78, 0x22, 0x1E8D}, {
740         0x5A, 0x5E, 0x1E90}, {
741         0x7A, 0x5E, 0x1E91}, {
742         0x74, 0x22, 0x1E97}, {
743         0x77, 0x2A, 0x1E98}, {
744         0x79, 0x2A, 0x1E99}, {
745         0x45, 0x7E, 0x1EBC}, {
746         0x65, 0x7E, 0x1EBD}, {
747         0x59, 0x60, 0x1EF2}, {
748         0x79, 0x60, 0x1EF3}, {
749         0x59, 0x7E, 0x1EF8}, {
750         0x79, 0x7E, 0x1EF9},
751             /* Compatible/possibles from UCS */
752         {
753         0x49, 0x4A, 0x0132}, {
754         0x69, 0x6A, 0x0133}, {
755         0x4C, 0x4A, 0x01C7}, {
756         0x4C, 0x6A, 0x01C8}, {
757         0x6C, 0x6A, 0x01C9}, {
758         0x4E, 0x4A, 0x01CA}, {
759         0x4E, 0x6A, 0x01CB}, {
760         0x6E, 0x6A, 0x01CC}, {
761         0x44, 0x5A, 0x01F1}, {
762         0x44, 0x7A, 0x01F2}, {
763         0x64, 0x7A, 0x01F3}, {
764         0x2E, 0x2E, 0x2025}, {
765         0x21, 0x21, 0x203C}, {
766         0x3F, 0x21, 0x2048}, {
767         0x21, 0x3F, 0x2049}, {
768         0x52, 0x73, 0x20A8}, {
769         0x4E, 0x6F, 0x2116}, {
770         0x53, 0x4D, 0x2120}, {
771         0x54, 0x4D, 0x2122}, {
772         0x49, 0x49, 0x2161}, {
773         0x49, 0x56, 0x2163}, {
774         0x56, 0x49, 0x2165}, {
775         0x49, 0x58, 0x2168}, {
776         0x58, 0x49, 0x216A}, {
777         0x69, 0x69, 0x2171}, {
778         0x69, 0x76, 0x2173}, {
779         0x76, 0x69, 0x2175}, {
780         0x69, 0x78, 0x2178}, {
781         0x78, 0x69, 0x217A}, {
782         0x31, 0x30, 0x2469}, {
783         0x31, 0x31, 0x246A}, {
784         0x31, 0x32, 0x246B}, {
785         0x31, 0x33, 0x246C}, {
786         0x31, 0x34, 0x246D}, {
787         0x31, 0x35, 0x246E}, {
788         0x31, 0x36, 0x246F}, {
789         0x31, 0x37, 0x2470}, {
790         0x31, 0x38, 0x2471}, {
791         0x31, 0x39, 0x2472}, {
792         0x32, 0x30, 0x2473}, {
793         0x31, 0x2E, 0x2488}, {
794         0x32, 0x2E, 0x2489}, {
795         0x33, 0x2E, 0x248A}, {
796         0x34, 0x2E, 0x248B}, {
797         0x35, 0x2E, 0x248C}, {
798         0x36, 0x2E, 0x248D}, {
799         0x37, 0x2E, 0x248E}, {
800         0x38, 0x2E, 0x248F}, {
801         0x39, 0x2E, 0x2490}, {
802         0x64, 0x61, 0x3372}, {
803         0x41, 0x55, 0x3373}, {
804         0x6F, 0x56, 0x3375}, {
805         0x70, 0x63, 0x3376}, {
806         0x70, 0x41, 0x3380}, {
807         0x6E, 0x41, 0x3381}, {
808         0x6D, 0x41, 0x3383}, {
809         0x6B, 0x41, 0x3384}, {
810         0x4B, 0x42, 0x3385}, {
811         0x4D, 0x42, 0x3386}, {
812         0x47, 0x42, 0x3387}, {
813         0x70, 0x46, 0x338A}, {
814         0x6E, 0x46, 0x338B}, {
815         0x6D, 0x67, 0x338E}, {
816         0x6B, 0x67, 0x338F}, {
817         0x48, 0x7A, 0x3390}, {
818         0x66, 0x6D, 0x3399}, {
819         0x6E, 0x6D, 0x339A}, {
820         0x6D, 0x6D, 0x339C}, {
821         0x63, 0x6D, 0x339D}, {
822         0x6B, 0x6D, 0x339E}, {
823         0x50, 0x61, 0x33A9}, {
824         0x70, 0x73, 0x33B0}, {
825         0x6E, 0x73, 0x33B1}, {
826         0x6D, 0x73, 0x33B3}, {
827         0x70, 0x56, 0x33B4}, {
828         0x6E, 0x56, 0x33B5}, {
829         0x6D, 0x56, 0x33B7}, {
830         0x6B, 0x56, 0x33B8}, {
831         0x4D, 0x56, 0x33B9}, {
832         0x70, 0x57, 0x33BA}, {
833         0x6E, 0x57, 0x33BB}, {
834         0x6D, 0x57, 0x33BD}, {
835         0x6B, 0x57, 0x33BE}, {
836         0x4D, 0x57, 0x33BF}, {
837         0x42, 0x71, 0x33C3}, {
838         0x63, 0x63, 0x33C4}, {
839         0x63, 0x64, 0x33C5}, {
840         0x64, 0x42, 0x33C8}, {
841         0x47, 0x79, 0x33C9}, {
842         0x68, 0x61, 0x33CA}, {
843         0x48, 0x50, 0x33CB}, {
844         0x69, 0x6E, 0x33CC}, {
845         0x4B, 0x4B, 0x33CD}, {
846         0x4B, 0x4D, 0x33CE}, {
847         0x6B, 0x74, 0x33CF}, {
848         0x6C, 0x6D, 0x33D0}, {
849         0x6C, 0x6E, 0x33D1}, {
850         0x6C, 0x78, 0x33D3}, {
851         0x6D, 0x62, 0x33D4}, {
852         0x50, 0x48, 0x33D7}, {
853         0x50, 0x52, 0x33DA}, {
854         0x73, 0x72, 0x33DB}, {
855         0x53, 0x76, 0x33DC}, {
856         0x57, 0x62, 0x33DD}, {
857         0x66, 0x66, 0xFB00}, {
858         0x66, 0x69, 0xFB01}, {
859         0x66, 0x6C, 0xFB02}, {
860         0x73, 0x74, 0xFB06}, {
861         0, 0, 0}
862     }, *c;
863
864     static int recurse = 0;
865     int nc = -1;
866
867     for (c = composetbl; c->first; c++) {
868         if (c->first == first && c->second == second)
869             return c->composed;
870     }
871
872     if (recurse == 0) {
873         recurse = 1;
874         nc = check_compose(second, first);
875         if (nc == -1)
876             nc = check_compose(toupper(first), toupper(second));
877         if (nc == -1)
878             nc = check_compose(toupper(second), toupper(first));
879         recurse = 0;
880     }
881     return nc;
882 }
883
884 int decode_codepage(char *cp_name)
885 {
886     char *s, *d;
887     struct cp_list_item *cpi;
888     int codepage = -1;
889     CPINFO cpinfo;
890
891     if (!*cp_name) {
892         /*
893          * Here we select a plausible default code page based on
894          * the locale the user is in. We wish to select an ISO code
895          * page or appropriate local default _rather_ than go with
896          * the Win125* series, because it's more important to have
897          * CSI and friends enabled by default than the ghastly
898          * Windows extra quote characters, and because it's more
899          * likely the user is connecting to a remote server that
900          * does something Unixy or VMSy and hence standards-
901          * compliant than that they're connecting back to a Windows
902          * box using horrible nonstandard charsets.
903          * 
904          * Accordingly, Robert de Bath suggests a method for
905          * picking a default character set that runs as follows:
906          * first call GetACP to get the system's ANSI code page
907          * identifier, and translate as follows:
908          * 
909          * 1250 -> ISO 8859-2
910          * 1251 -> KOI8-U
911          * 1252 -> ISO 8859-1
912          * 1253 -> ISO 8859-7
913          * 1254 -> ISO 8859-9
914          * 1255 -> ISO 8859-8
915          * 1256 -> ISO 8859-6
916          * 1257 -> ISO 8859-4
917          * 
918          * and for anything else, choose direct-to-font.
919          */
920         int cp = GetACP();
921         switch (cp) {
922           case 1250: cp_name = "ISO-8859-2"; break;
923           case 1251: cp_name = "KOI8-U"; break;
924           case 1252: cp_name = "ISO-8859-1"; break;
925           case 1253: cp_name = "ISO-8859-7"; break;
926           case 1254: cp_name = "ISO-8859-9"; break;
927           case 1255: cp_name = "ISO-8859-8"; break;
928           case 1256: cp_name = "ISO-8859-6"; break;
929           case 1257: cp_name = "ISO-8859-4"; break;
930             /* default: leave it blank, which will select -1, direct->font */
931         }
932     }
933
934     if (cp_name && *cp_name)
935         for (cpi = cp_list; cpi->name; cpi++) {
936             s = cp_name;
937             d = cpi->name;
938             for (;;) {
939                 while (*s && !isalnum(*s) && *s != ':')
940                     s++;
941                 while (*d && !isalnum(*d) && *d != ':')
942                     d++;
943                 if (*s == 0) {
944                     codepage = cpi->codepage;
945                     if (codepage == CP_UTF8)
946                         goto break_break;
947                     if (codepage == 0) {
948                         codepage = 65536 + (cpi - cp_list);
949                         goto break_break;
950                     }
951
952                     if (GetCPInfo(codepage, &cpinfo) != 0)
953                         goto break_break;
954                 }
955                 if (tolower(*s++) != tolower(*d++))
956                     break;
957             }
958         }
959
960     if (cp_name && *cp_name) {
961         d = cp_name;
962         if (tolower(d[0]) == 'c' && tolower(d[1]) == 'p')
963             d += 2;
964         if (tolower(d[0]) == 'i' && tolower(d[1]) == 'b'
965             && tolower(d[1]) == 'm')
966             d += 3;
967         for (s = d; *s >= '0' && *s <= '9'; s++);
968         if (*s == 0 && s != d)
969             codepage = atoi(d);        /* CP999 or IBM999 */
970
971         if (codepage == CP_ACP)
972             codepage = GetACP();
973         if (codepage == CP_OEMCP)
974             codepage = GetOEMCP();
975         if (codepage > 65535)
976             codepage = -2;
977     }
978
979   break_break:;
980     if (codepage != -1) {
981         if (codepage != CP_UTF8 && codepage < 65536) {
982             if (GetCPInfo(codepage, &cpinfo) == 0) {
983                 codepage = -2;
984             } else if (cpinfo.MaxCharSize > 1)
985                 codepage = -3;
986         }
987     }
988     if (codepage == -1 && *cp_name)
989         codepage = -2;
990     return codepage;
991 }
992
993 char *cp_name(int codepage)
994 {
995     struct cp_list_item *cpi, *cpno;
996     static char buf[32];
997
998     if (codepage == -1) {
999         sprintf(buf, "Use font encoding");
1000         return buf;
1001     }
1002
1003     if (codepage > 0 && codepage < 65536)
1004         sprintf(buf, "CP%03d", codepage);
1005     else
1006         *buf = 0;
1007
1008     if (codepage >= 65536) {
1009         cpno = 0;
1010         for (cpi = cp_list; cpi->name; cpi++)
1011             if (cpi == cp_list + (codepage - 65536)) {
1012                 cpno = cpi;
1013                 break;
1014             }
1015         if (cpno)
1016             for (cpi = cp_list; cpi->name; cpi++) {
1017                 if (cpno->cp_table == cpi->cp_table)
1018                     return cpi->name;
1019             }
1020     } else {
1021         for (cpi = cp_list; cpi->name; cpi++) {
1022             if (codepage == cpi->codepage)
1023                 return cpi->name;
1024         }
1025     }
1026     return buf;
1027 }
1028
1029 /*
1030  * Return the nth code page in the list, for use in the GUI
1031  * configurer.
1032  */
1033 char *cp_enumerate(int index)
1034 {
1035     if (index < 0 || index >= lenof(cp_list))
1036         return NULL;
1037     return cp_list[index].name;
1038 }
1039
1040 static void get_unitab(int codepage, wchar_t * unitab, int ftype)
1041 {
1042     char tbuf[4];
1043     int i, max = 256, flg = MB_ERR_INVALID_CHARS;
1044
1045     if (ftype)
1046         flg |= MB_USEGLYPHCHARS;
1047     if (ftype == 2)
1048         max = 128;
1049
1050     if (codepage == CP_UTF8)
1051         codepage = 28591;
1052     else if (codepage == CP_ACP)
1053         codepage = GetACP();
1054     else if (codepage == CP_OEMCP)
1055         codepage = GetOEMCP();
1056
1057     if (codepage > 0 && codepage < 65536) {
1058         for (i = 0; i < max; i++) {
1059             tbuf[0] = i;
1060
1061             if (MultiByteToWideChar(codepage, flg, tbuf, 1, unitab + i, 1)
1062                 != 1)
1063                 unitab[i] = 0xFFFD;
1064         }
1065     } else {
1066         int j = 256 - cp_list[codepage & 0xFFFF].cp_size;
1067         for (i = 0; i < max; i++)
1068             unitab[i] = i;
1069         for (i = j; i < max; i++)
1070             unitab[i] = cp_list[codepage & 0xFFFF].cp_table[i - j];
1071     }
1072 }