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