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