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