]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unicode.c
Fix to link_font() from RDB. I must get him to comment some of this :-)
[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     /* Last chance, if !unicode then try poorman links. */
397     if (cfg.vtmode != VT_UNICODE) {
398         static char poorman_scoacs[] = 
399             "CueaaaaceeeiiiAAE**ooouuyOUc$YPsaiounNao?++**!<>###||||++||++++++--|-+||++--|-+----++++++++##||#aBTPEsyt******EN=+><++-=... n2* ";
400         static char poorman_latin1[] =
401             " !cL.Y|S\"Ca<--R~o+23'u|.,1o>///?AAAAAAACEEEEIIIIDNOOOOOxOUUUUYPBaaaaaaaceeeeiiiionooooo/ouuuuypy";
402         static char poorman_vt100[] = "*#****o~**+++++-----++++|****L.";
403
404         for (i = 160; i < 256; i++)
405             if (!DIRECT_FONT(unitab_line[i]) &&
406                 unitab_line[i] >= 160 && unitab_line[i] < 256)
407                 unitab_line[i] = (WCHAR) (ATTR_ACP
408                                           + poorman_latin1[unitab_line[i] -
409                                                            160]);
410         for (i = 96; i < 127; i++)
411             if (!DIRECT_FONT(unitab_xterm[i]))
412                 unitab_xterm[i] =
413                     (WCHAR) (ATTR_ACP + poorman_vt100[i - 96]);
414         for(i=128;i<256;i++) 
415             if (!DIRECT_FONT(unitab_scoacs[i]))
416                 unitab_scoacs[i] = 
417                     (WCHAR) (ATTR_ACP + poorman_scoacs[i - 128]);
418     }
419 }
420
421 static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr)
422 {
423     int font_index, line_index, i;
424     for (line_index = 0; line_index < 256; line_index++) {
425         if (DIRECT_FONT(line_tbl[line_index]))
426             continue;
427         for(i = 0; i < 256; i++) {
428             font_index = ((32 + i) & 0xFF);
429             if (line_tbl[line_index] == font_tbl[font_index]) {
430                 line_tbl[line_index] = (WCHAR) (attr + font_index);
431                 break;
432             }
433         }
434     }
435 }
436
437 void lpage_send(int codepage, char *buf, int len)
438 {
439     static wchar_t *widebuffer = 0;
440     static int widesize = 0;
441     int wclen;
442
443     if (codepage < 0) {
444         ldisc_send(buf, len);
445         return;
446     }
447
448     if (len > widesize) {
449         sfree(widebuffer);
450         widebuffer = smalloc(len * 2 * sizeof(wchar_t));
451         widesize = len * 2;
452     }
453
454     wclen =
455         MultiByteToWideChar(codepage, 0, buf, len, widebuffer, widesize);
456     luni_send(widebuffer, wclen);
457 }
458
459 void luni_send(wchar_t * widebuf, int len)
460 {
461     static char *linebuffer = 0;
462     static int linesize = 0;
463     int ratio = (in_utf)?3:1;
464     int i;
465     char *p;
466
467     if (len * ratio > linesize) {
468         sfree(linebuffer);
469         linebuffer = smalloc(len * ratio * 2 * sizeof(wchar_t));
470         linesize = len * ratio * 2;
471     }
472
473     if (in_utf) {
474         /* UTF is a simple algorithm */
475         for (p = linebuffer, i = 0; i < len; i++) {
476             wchar_t ch = widebuf[i];
477             /* Windows wchar_t is UTF-16 */
478             if ((ch&0xF800) == 0xD800) ch = '.';
479
480             if (ch < 0x80) {
481                 *p++ = (char) (ch);
482             } else if (ch < 0x800) {
483                 *p++ = (0xC0 | (ch >> 6));
484                 *p++ = (0x80 | (ch & 0x3F));
485             } else {
486                 *p++ = (0xE0 | (ch >> 12));
487                 *p++ = (0x80 | ((ch >> 6) & 0x3F));
488                 *p++ = (0x80 | (ch & 0x3F));
489             }
490         }
491     } else if (!uni_tbl) {
492         int rv;
493         rv = WideCharToMultiByte(line_codepage, 0, widebuf, len,
494                                  linebuffer, linesize, NULL, NULL);
495         if (rv >= 0)
496             p = linebuffer + rv;
497         else
498             p = linebuffer;
499     } else {
500         /* Others are a lookup in an array */
501         for (p = linebuffer, i = 0; i < len; i++) {
502             wchar_t ch = widebuf[i];
503             int by;
504             char *p1;
505             if (uni_tbl && (p1 = uni_tbl[(ch >> 8) & 0xFF])
506                 && (by = p1[ch & 0xFF]))
507                 *p++ = by;
508             else if (ch < 0x80)
509                 *p++ = (char) ch;
510 #if 1
511             else
512                 *p++ = '.';
513 #endif
514         }
515     }
516     if (p > linebuffer)
517         ldisc_send(linebuffer, p - linebuffer);
518 }
519
520 int check_compose(int first, int second)
521 {
522
523     static struct {
524         char first, second;
525         wchar_t composed;
526     } composetbl[] = {
527         {
528         0x2b, 0x2b, 0x0023}, {
529         0x41, 0x41, 0x0040}, {
530         0x28, 0x28, 0x005b}, {
531         0x2f, 0x2f, 0x005c}, {
532         0x29, 0x29, 0x005d}, {
533         0x28, 0x2d, 0x007b}, {
534         0x2d, 0x29, 0x007d}, {
535         0x2f, 0x5e, 0x007c}, {
536         0x21, 0x21, 0x00a1}, {
537         0x43, 0x2f, 0x00a2}, {
538         0x43, 0x7c, 0x00a2}, {
539         0x4c, 0x2d, 0x00a3}, {
540         0x4c, 0x3d, 0x00a3}, {
541         0x58, 0x4f, 0x00a4}, {
542         0x58, 0x30, 0x00a4}, {
543         0x59, 0x2d, 0x00a5}, {
544         0x59, 0x3d, 0x00a5}, {
545         0x7c, 0x7c, 0x00a6}, {
546         0x53, 0x4f, 0x00a7}, {
547         0x53, 0x21, 0x00a7}, {
548         0x53, 0x30, 0x00a7}, {
549         0x22, 0x22, 0x00a8}, {
550         0x43, 0x4f, 0x00a9}, {
551         0x43, 0x30, 0x00a9}, {
552         0x41, 0x5f, 0x00aa}, {
553         0x3c, 0x3c, 0x00ab}, {
554         0x2c, 0x2d, 0x00ac}, {
555         0x2d, 0x2d, 0x00ad}, {
556         0x52, 0x4f, 0x00ae}, {
557         0x2d, 0x5e, 0x00af}, {
558         0x30, 0x5e, 0x00b0}, {
559         0x2b, 0x2d, 0x00b1}, {
560         0x32, 0x5e, 0x00b2}, {
561         0x33, 0x5e, 0x00b3}, {
562         0x27, 0x27, 0x00b4}, {
563         0x2f, 0x55, 0x00b5}, {
564         0x50, 0x21, 0x00b6}, {
565         0x2e, 0x5e, 0x00b7}, {
566         0x2c, 0x2c, 0x00b8}, {
567         0x31, 0x5e, 0x00b9}, {
568         0x4f, 0x5f, 0x00ba}, {
569         0x3e, 0x3e, 0x00bb}, {
570         0x31, 0x34, 0x00bc}, {
571         0x31, 0x32, 0x00bd}, {
572         0x33, 0x34, 0x00be}, {
573         0x3f, 0x3f, 0x00bf}, {
574         0x60, 0x41, 0x00c0}, {
575         0x27, 0x41, 0x00c1}, {
576         0x5e, 0x41, 0x00c2}, {
577         0x7e, 0x41, 0x00c3}, {
578         0x22, 0x41, 0x00c4}, {
579         0x2a, 0x41, 0x00c5}, {
580         0x41, 0x45, 0x00c6}, {
581         0x2c, 0x43, 0x00c7}, {
582         0x60, 0x45, 0x00c8}, {
583         0x27, 0x45, 0x00c9}, {
584         0x5e, 0x45, 0x00ca}, {
585         0x22, 0x45, 0x00cb}, {
586         0x60, 0x49, 0x00cc}, {
587         0x27, 0x49, 0x00cd}, {
588         0x5e, 0x49, 0x00ce}, {
589         0x22, 0x49, 0x00cf}, {
590         0x2d, 0x44, 0x00d0}, {
591         0x7e, 0x4e, 0x00d1}, {
592         0x60, 0x4f, 0x00d2}, {
593         0x27, 0x4f, 0x00d3}, {
594         0x5e, 0x4f, 0x00d4}, {
595         0x7e, 0x4f, 0x00d5}, {
596         0x22, 0x4f, 0x00d6}, {
597         0x58, 0x58, 0x00d7}, {
598         0x2f, 0x4f, 0x00d8}, {
599         0x60, 0x55, 0x00d9}, {
600         0x27, 0x55, 0x00da}, {
601         0x5e, 0x55, 0x00db}, {
602         0x22, 0x55, 0x00dc}, {
603         0x27, 0x59, 0x00dd}, {
604         0x48, 0x54, 0x00de}, {
605         0x73, 0x73, 0x00df}, {
606         0x60, 0x61, 0x00e0}, {
607         0x27, 0x61, 0x00e1}, {
608         0x5e, 0x61, 0x00e2}, {
609         0x7e, 0x61, 0x00e3}, {
610         0x22, 0x61, 0x00e4}, {
611         0x2a, 0x61, 0x00e5}, {
612         0x61, 0x65, 0x00e6}, {
613         0x2c, 0x63, 0x00e7}, {
614         0x60, 0x65, 0x00e8}, {
615         0x27, 0x65, 0x00e9}, {
616         0x5e, 0x65, 0x00ea}, {
617         0x22, 0x65, 0x00eb}, {
618         0x60, 0x69, 0x00ec}, {
619         0x27, 0x69, 0x00ed}, {
620         0x5e, 0x69, 0x00ee}, {
621         0x22, 0x69, 0x00ef}, {
622         0x2d, 0x64, 0x00f0}, {
623         0x7e, 0x6e, 0x00f1}, {
624         0x60, 0x6f, 0x00f2}, {
625         0x27, 0x6f, 0x00f3}, {
626         0x5e, 0x6f, 0x00f4}, {
627         0x7e, 0x6f, 0x00f5}, {
628         0x22, 0x6f, 0x00f6}, {
629         0x3a, 0x2d, 0x00f7}, {
630         0x6f, 0x2f, 0x00f8}, {
631         0x60, 0x75, 0x00f9}, {
632         0x27, 0x75, 0x00fa}, {
633         0x5e, 0x75, 0x00fb}, {
634         0x22, 0x75, 0x00fc}, {
635         0x27, 0x79, 0x00fd}, {
636         0x68, 0x74, 0x00fe}, {
637         0x22, 0x79, 0x00ff},
638             /* Unicode extras. */
639         {
640         0x6f, 0x65, 0x0153}, {
641         0x4f, 0x45, 0x0152},
642             /* Compose pairs from UCS */
643         {
644         0x41, 0x2D, 0x0100}, {
645         0x61, 0x2D, 0x0101}, {
646         0x43, 0x27, 0x0106}, {
647         0x63, 0x27, 0x0107}, {
648         0x43, 0x5E, 0x0108}, {
649         0x63, 0x5E, 0x0109}, {
650         0x45, 0x2D, 0x0112}, {
651         0x65, 0x2D, 0x0113}, {
652         0x47, 0x5E, 0x011C}, {
653         0x67, 0x5E, 0x011D}, {
654         0x47, 0x2C, 0x0122}, {
655         0x67, 0x2C, 0x0123}, {
656         0x48, 0x5E, 0x0124}, {
657         0x68, 0x5E, 0x0125}, {
658         0x49, 0x7E, 0x0128}, {
659         0x69, 0x7E, 0x0129}, {
660         0x49, 0x2D, 0x012A}, {
661         0x69, 0x2D, 0x012B}, {
662         0x4A, 0x5E, 0x0134}, {
663         0x6A, 0x5E, 0x0135}, {
664         0x4B, 0x2C, 0x0136}, {
665         0x6B, 0x2C, 0x0137}, {
666         0x4C, 0x27, 0x0139}, {
667         0x6C, 0x27, 0x013A}, {
668         0x4C, 0x2C, 0x013B}, {
669         0x6C, 0x2C, 0x013C}, {
670         0x4E, 0x27, 0x0143}, {
671         0x6E, 0x27, 0x0144}, {
672         0x4E, 0x2C, 0x0145}, {
673         0x6E, 0x2C, 0x0146}, {
674         0x4F, 0x2D, 0x014C}, {
675         0x6F, 0x2D, 0x014D}, {
676         0x52, 0x27, 0x0154}, {
677         0x72, 0x27, 0x0155}, {
678         0x52, 0x2C, 0x0156}, {
679         0x72, 0x2C, 0x0157}, {
680         0x53, 0x27, 0x015A}, {
681         0x73, 0x27, 0x015B}, {
682         0x53, 0x5E, 0x015C}, {
683         0x73, 0x5E, 0x015D}, {
684         0x53, 0x2C, 0x015E}, {
685         0x73, 0x2C, 0x015F}, {
686         0x54, 0x2C, 0x0162}, {
687         0x74, 0x2C, 0x0163}, {
688         0x55, 0x7E, 0x0168}, {
689         0x75, 0x7E, 0x0169}, {
690         0x55, 0x2D, 0x016A}, {
691         0x75, 0x2D, 0x016B}, {
692         0x55, 0x2A, 0x016E}, {
693         0x75, 0x2A, 0x016F}, {
694         0x57, 0x5E, 0x0174}, {
695         0x77, 0x5E, 0x0175}, {
696         0x59, 0x5E, 0x0176}, {
697         0x79, 0x5E, 0x0177}, {
698         0x59, 0x22, 0x0178}, {
699         0x5A, 0x27, 0x0179}, {
700         0x7A, 0x27, 0x017A}, {
701         0x47, 0x27, 0x01F4}, {
702         0x67, 0x27, 0x01F5}, {
703         0x4E, 0x60, 0x01F8}, {
704         0x6E, 0x60, 0x01F9}, {
705         0x45, 0x2C, 0x0228}, {
706         0x65, 0x2C, 0x0229}, {
707         0x59, 0x2D, 0x0232}, {
708         0x79, 0x2D, 0x0233}, {
709         0x44, 0x2C, 0x1E10}, {
710         0x64, 0x2C, 0x1E11}, {
711         0x47, 0x2D, 0x1E20}, {
712         0x67, 0x2D, 0x1E21}, {
713         0x48, 0x22, 0x1E26}, {
714         0x68, 0x22, 0x1E27}, {
715         0x48, 0x2C, 0x1E28}, {
716         0x68, 0x2C, 0x1E29}, {
717         0x4B, 0x27, 0x1E30}, {
718         0x6B, 0x27, 0x1E31}, {
719         0x4D, 0x27, 0x1E3E}, {
720         0x6D, 0x27, 0x1E3F}, {
721         0x50, 0x27, 0x1E54}, {
722         0x70, 0x27, 0x1E55}, {
723         0x56, 0x7E, 0x1E7C}, {
724         0x76, 0x7E, 0x1E7D}, {
725         0x57, 0x60, 0x1E80}, {
726         0x77, 0x60, 0x1E81}, {
727         0x57, 0x27, 0x1E82}, {
728         0x77, 0x27, 0x1E83}, {
729         0x57, 0x22, 0x1E84}, {
730         0x77, 0x22, 0x1E85}, {
731         0x58, 0x22, 0x1E8C}, {
732         0x78, 0x22, 0x1E8D}, {
733         0x5A, 0x5E, 0x1E90}, {
734         0x7A, 0x5E, 0x1E91}, {
735         0x74, 0x22, 0x1E97}, {
736         0x77, 0x2A, 0x1E98}, {
737         0x79, 0x2A, 0x1E99}, {
738         0x45, 0x7E, 0x1EBC}, {
739         0x65, 0x7E, 0x1EBD}, {
740         0x59, 0x60, 0x1EF2}, {
741         0x79, 0x60, 0x1EF3}, {
742         0x59, 0x7E, 0x1EF8}, {
743         0x79, 0x7E, 0x1EF9},
744             /* Compatible/possibles from UCS */
745         {
746         0x49, 0x4A, 0x0132}, {
747         0x69, 0x6A, 0x0133}, {
748         0x4C, 0x4A, 0x01C7}, {
749         0x4C, 0x6A, 0x01C8}, {
750         0x6C, 0x6A, 0x01C9}, {
751         0x4E, 0x4A, 0x01CA}, {
752         0x4E, 0x6A, 0x01CB}, {
753         0x6E, 0x6A, 0x01CC}, {
754         0x44, 0x5A, 0x01F1}, {
755         0x44, 0x7A, 0x01F2}, {
756         0x64, 0x7A, 0x01F3}, {
757         0x2E, 0x2E, 0x2025}, {
758         0x21, 0x21, 0x203C}, {
759         0x3F, 0x21, 0x2048}, {
760         0x21, 0x3F, 0x2049}, {
761         0x52, 0x73, 0x20A8}, {
762         0x4E, 0x6F, 0x2116}, {
763         0x53, 0x4D, 0x2120}, {
764         0x54, 0x4D, 0x2122}, {
765         0x49, 0x49, 0x2161}, {
766         0x49, 0x56, 0x2163}, {
767         0x56, 0x49, 0x2165}, {
768         0x49, 0x58, 0x2168}, {
769         0x58, 0x49, 0x216A}, {
770         0x69, 0x69, 0x2171}, {
771         0x69, 0x76, 0x2173}, {
772         0x76, 0x69, 0x2175}, {
773         0x69, 0x78, 0x2178}, {
774         0x78, 0x69, 0x217A}, {
775         0x31, 0x30, 0x2469}, {
776         0x31, 0x31, 0x246A}, {
777         0x31, 0x32, 0x246B}, {
778         0x31, 0x33, 0x246C}, {
779         0x31, 0x34, 0x246D}, {
780         0x31, 0x35, 0x246E}, {
781         0x31, 0x36, 0x246F}, {
782         0x31, 0x37, 0x2470}, {
783         0x31, 0x38, 0x2471}, {
784         0x31, 0x39, 0x2472}, {
785         0x32, 0x30, 0x2473}, {
786         0x31, 0x2E, 0x2488}, {
787         0x32, 0x2E, 0x2489}, {
788         0x33, 0x2E, 0x248A}, {
789         0x34, 0x2E, 0x248B}, {
790         0x35, 0x2E, 0x248C}, {
791         0x36, 0x2E, 0x248D}, {
792         0x37, 0x2E, 0x248E}, {
793         0x38, 0x2E, 0x248F}, {
794         0x39, 0x2E, 0x2490}, {
795         0x64, 0x61, 0x3372}, {
796         0x41, 0x55, 0x3373}, {
797         0x6F, 0x56, 0x3375}, {
798         0x70, 0x63, 0x3376}, {
799         0x70, 0x41, 0x3380}, {
800         0x6E, 0x41, 0x3381}, {
801         0x6D, 0x41, 0x3383}, {
802         0x6B, 0x41, 0x3384}, {
803         0x4B, 0x42, 0x3385}, {
804         0x4D, 0x42, 0x3386}, {
805         0x47, 0x42, 0x3387}, {
806         0x70, 0x46, 0x338A}, {
807         0x6E, 0x46, 0x338B}, {
808         0x6D, 0x67, 0x338E}, {
809         0x6B, 0x67, 0x338F}, {
810         0x48, 0x7A, 0x3390}, {
811         0x66, 0x6D, 0x3399}, {
812         0x6E, 0x6D, 0x339A}, {
813         0x6D, 0x6D, 0x339C}, {
814         0x63, 0x6D, 0x339D}, {
815         0x6B, 0x6D, 0x339E}, {
816         0x50, 0x61, 0x33A9}, {
817         0x70, 0x73, 0x33B0}, {
818         0x6E, 0x73, 0x33B1}, {
819         0x6D, 0x73, 0x33B3}, {
820         0x70, 0x56, 0x33B4}, {
821         0x6E, 0x56, 0x33B5}, {
822         0x6D, 0x56, 0x33B7}, {
823         0x6B, 0x56, 0x33B8}, {
824         0x4D, 0x56, 0x33B9}, {
825         0x70, 0x57, 0x33BA}, {
826         0x6E, 0x57, 0x33BB}, {
827         0x6D, 0x57, 0x33BD}, {
828         0x6B, 0x57, 0x33BE}, {
829         0x4D, 0x57, 0x33BF}, {
830         0x42, 0x71, 0x33C3}, {
831         0x63, 0x63, 0x33C4}, {
832         0x63, 0x64, 0x33C5}, {
833         0x64, 0x42, 0x33C8}, {
834         0x47, 0x79, 0x33C9}, {
835         0x68, 0x61, 0x33CA}, {
836         0x48, 0x50, 0x33CB}, {
837         0x69, 0x6E, 0x33CC}, {
838         0x4B, 0x4B, 0x33CD}, {
839         0x4B, 0x4D, 0x33CE}, {
840         0x6B, 0x74, 0x33CF}, {
841         0x6C, 0x6D, 0x33D0}, {
842         0x6C, 0x6E, 0x33D1}, {
843         0x6C, 0x78, 0x33D3}, {
844         0x6D, 0x62, 0x33D4}, {
845         0x50, 0x48, 0x33D7}, {
846         0x50, 0x52, 0x33DA}, {
847         0x73, 0x72, 0x33DB}, {
848         0x53, 0x76, 0x33DC}, {
849         0x57, 0x62, 0x33DD}, {
850         0x66, 0x66, 0xFB00}, {
851         0x66, 0x69, 0xFB01}, {
852         0x66, 0x6C, 0xFB02}, {
853         0x73, 0x74, 0xFB06}, {
854         0, 0, 0}
855     }, *c;
856
857     static int recurse = 0;
858     int nc = -1;
859
860     for (c = composetbl; c->first; c++) {
861         if (c->first == first && c->second == second)
862             return c->composed;
863     }
864
865     if (recurse == 0) {
866         recurse = 1;
867         nc = check_compose(second, first);
868         if (nc == -1)
869             nc = check_compose(toupper(first), toupper(second));
870         if (nc == -1)
871             nc = check_compose(toupper(second), toupper(first));
872         recurse = 0;
873     }
874     return nc;
875 }
876
877 int decode_codepage(char *cp_name)
878 {
879     char *s, *d;
880     struct cp_list_item *cpi;
881     int codepage = -1;
882     CPINFO cpinfo;
883
884     if (!*cp_name) {
885         /*
886          * Here we select a plausible default code page based on
887          * the locale the user is in. We wish to select an ISO code
888          * page or appropriate local default _rather_ than go with
889          * the Win125* series, because it's more important to have
890          * CSI and friends enabled by default than the ghastly
891          * Windows extra quote characters, and because it's more
892          * likely the user is connecting to a remote server that
893          * does something Unixy or VMSy and hence standards-
894          * compliant than that they're connecting back to a Windows
895          * box using horrible nonstandard charsets.
896          * 
897          * Accordingly, Robert de Bath suggests a method for
898          * picking a default character set that runs as follows:
899          * first call GetACP to get the system's ANSI code page
900          * identifier, and translate as follows:
901          * 
902          * 1250 -> ISO 8859-2
903          * 1251 -> KOI8-U
904          * 1252 -> ISO 8859-1
905          * 1253 -> ISO 8859-7
906          * 1254 -> ISO 8859-9
907          * 1255 -> ISO 8859-8
908          * 1256 -> ISO 8859-6
909          * 1257 -> ISO 8859-4
910          * 
911          * and for anything else, choose direct-to-font.
912          */
913         int cp = GetACP();
914         switch (cp) {
915           case 1250: cp_name = "ISO-8859-2"; break;
916           case 1251: cp_name = "KOI8-U"; break;
917           case 1252: cp_name = "ISO-8859-1"; break;
918           case 1253: cp_name = "ISO-8859-7"; break;
919           case 1254: cp_name = "ISO-8859-9"; break;
920           case 1255: cp_name = "ISO-8859-8"; break;
921           case 1256: cp_name = "ISO-8859-6"; break;
922           case 1257: cp_name = "ISO-8859-4"; break;
923             /* default: leave it blank, which will select -1, direct->font */
924         }
925     }
926
927     if (cp_name && *cp_name)
928         for (cpi = cp_list; cpi->name; cpi++) {
929             s = cp_name;
930             d = cpi->name;
931             for (;;) {
932                 while (*s && !isalnum(*s) && *s != ':')
933                     s++;
934                 while (*d && !isalnum(*d) && *d != ':')
935                     d++;
936                 if (*s == 0) {
937                     codepage = cpi->codepage;
938                     if (codepage == CP_UTF8)
939                         goto break_break;
940                     if (codepage == 0) {
941                         codepage = 65536 + (cpi - cp_list);
942                         goto break_break;
943                     }
944
945                     if (GetCPInfo(codepage, &cpinfo) != 0)
946                         goto break_break;
947                 }
948                 if (tolower(*s++) != tolower(*d++))
949                     break;
950             }
951         }
952
953     if (cp_name && *cp_name) {
954         d = cp_name;
955         if (tolower(d[0]) == 'c' && tolower(d[1]) == 'p')
956             d += 2;
957         if (tolower(d[0]) == 'i' && tolower(d[1]) == 'b'
958             && tolower(d[1]) == 'm')
959             d += 3;
960         for (s = d; *s >= '0' && *s <= '9'; s++);
961         if (*s == 0 && s != d)
962             codepage = atoi(d);        /* CP999 or IBM999 */
963
964         if (codepage == CP_ACP)
965             codepage = GetACP();
966         if (codepage == CP_OEMCP)
967             codepage = GetOEMCP();
968         if (codepage > 65535)
969             codepage = -2;
970     }
971
972   break_break:;
973     if (codepage != -1) {
974         if (codepage != CP_UTF8 && codepage < 65536) {
975             if (GetCPInfo(codepage, &cpinfo) == 0) {
976                 codepage = -2;
977             } else if (cpinfo.MaxCharSize > 1)
978                 codepage = -3;
979         }
980     }
981     if (codepage == -1 && *cp_name)
982         codepage = -2;
983     return codepage;
984 }
985
986 char *cp_name(int codepage)
987 {
988     struct cp_list_item *cpi, *cpno;
989     static char buf[32];
990
991     if (codepage == -1) {
992         sprintf(buf, "Use font encoding");
993         return buf;
994     }
995
996     if (codepage > 0 && codepage < 65536)
997         sprintf(buf, "CP%03d", codepage);
998     else
999         *buf = 0;
1000
1001     if (codepage >= 65536) {
1002         cpno = 0;
1003         for (cpi = cp_list; cpi->name; cpi++)
1004             if (cpi == cp_list + (codepage - 65536)) {
1005                 cpno = cpi;
1006                 break;
1007             }
1008         if (cpno)
1009             for (cpi = cp_list; cpi->name; cpi++) {
1010                 if (cpno->cp_table == cpi->cp_table)
1011                     return cpi->name;
1012             }
1013     } else {
1014         for (cpi = cp_list; cpi->name; cpi++) {
1015             if (codepage == cpi->codepage)
1016                 return cpi->name;
1017         }
1018     }
1019     return buf;
1020 }
1021
1022 /*
1023  * Return the nth code page in the list, for use in the GUI
1024  * configurer.
1025  */
1026 char *cp_enumerate(int index)
1027 {
1028     if (index < 0 || index >= lenof(cp_list))
1029         return NULL;
1030     return cp_list[index].name;
1031 }
1032
1033 static void get_unitab(int codepage, wchar_t * unitab, int ftype)
1034 {
1035     char tbuf[4];
1036     int i, max = 256, flg = MB_ERR_INVALID_CHARS;
1037
1038     if (ftype)
1039         flg |= MB_USEGLYPHCHARS;
1040     if (ftype == 2)
1041         max = 128;
1042
1043     if (codepage == CP_UTF8)
1044         codepage = 28591;
1045     else if (codepage == CP_ACP)
1046         codepage = GetACP();
1047     else if (codepage == CP_OEMCP)
1048         codepage = GetOEMCP();
1049
1050     if (codepage > 0 && codepage < 65536) {
1051         for (i = 0; i < max; i++) {
1052             tbuf[0] = i;
1053
1054             if (MultiByteToWideChar(codepage, flg, tbuf, 1, unitab + i, 1)
1055                 != 1)
1056                 unitab[i] = 0xFFFD;
1057         }
1058     } else {
1059         int j = 256 - cp_list[codepage & 0xFFFF].cp_size;
1060         for (i = 0; i < max; i++)
1061             unitab[i] = i;
1062         for (i = j; i < max; i++)
1063             unitab[i] = cp_list[codepage & 0xFFFF].cp_table[i - j];
1064     }
1065 }