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