]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unicode.c
f8cd3b51c5d81ee65ee47f03970336ac9cdfff1c
[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
9 #include <time.h>
10 #include "putty.h"
11 #include "misc.h"
12
13 /* Character conversion arrays; they are usually taken from windows,
14  * the xterm one has the four scanlines that have no unicode 2.0
15  * equivalents mapped to their unicode 3.0 locations.
16  */
17 static char **uni_tbl;
18
19 static WCHAR unitab_xterm_std[32] = {
20     0x2666, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
21     0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
22     0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
23     0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x0020
24 };
25
26 /*
27  * If the codepage is non-zero it's a window codepage, zero means use a
28  * local codepage. The name is always converted to the first of any
29  * duplicate definitions.
30  */
31
32 /* 
33  * Tables for ISO-8859-{1-9,13-16} derived from those downloaded
34  * 2001-10-02 from <http://www.unicode.org/Public/MAPPINGS/> -- jtn
35  */
36
37 /* XXX: This could be done algorithmically, but I'm not sure it's
38  *      worth the hassle -- jtn */
39 /* ISO/IEC 8859-1:1998 (Latin-1, "Western", "West European") */
40 static wchar_t iso_8859_1[] = {
41     0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
42     0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
43     0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
44     0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
45     0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
46     0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
47     0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
48     0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
49     0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
50     0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
51     0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
52     0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
53 };
54
55 /* ISO 8859-2:1999 (Latin-2, "Central European", "East European") */
56 static wchar_t iso_8859_2[] = {
57     0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
58     0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
59     0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
60     0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
61     0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
62     0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
63     0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
64     0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
65     0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
66     0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
67     0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
68     0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
69 };
70
71 /* ISO/IEC 8859-3:1999 (Latin-3, "South European", "Maltese & Esperanto") */
72 static wchar_t iso_8859_3[] = {
73     0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFD, 0x0124, 0x00A7,
74     0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFD, 0x017B,
75     0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7,
76     0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFD, 0x017C,
77     0x00C0, 0x00C1, 0x00C2, 0xFFFD, 0x00C4, 0x010A, 0x0108, 0x00C7,
78     0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
79     0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7,
80     0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF,
81     0x00E0, 0x00E1, 0x00E2, 0xFFFD, 0x00E4, 0x010B, 0x0109, 0x00E7,
82     0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
83     0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7,
84     0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9
85 };
86
87 /* ISO/IEC 8859-4:1998 (Latin-4, "North European") */
88 static wchar_t iso_8859_4[] = {
89     0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7,
90     0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF,
91     0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7,
92     0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B,
93     0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
94     0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A,
95     0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
96     0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF,
97     0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
98     0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B,
99     0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
100     0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9
101 };
102
103 /* ISO 8859-5:1999 (Latin/Cyrillic) */
104 static wchar_t iso_8859_5[] = {
105     0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
106     0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F,
107     0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
108     0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
109     0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
110     0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
111     0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
112     0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
113     0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
114     0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
115     0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
116     0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F
117 };
118
119 /* ISO 8859-6:1999 (Latin/Arabic) */
120 static wchar_t iso_8859_6[] = {
121     0x00A0, 0xFFFD, 0xFFFD, 0xFFFD, 0x00A4, 0xFFFD, 0xFFFD, 0xFFFD,
122     0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x060C, 0x00AD, 0xFFFD, 0xFFFD,
123     0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
124     0xFFFD, 0xFFFD, 0xFFFD, 0x061B, 0xFFFD, 0xFFFD, 0xFFFD, 0x061F,
125     0xFFFD, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
126     0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
127     0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637,
128     0x0638, 0x0639, 0x063A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
129     0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647,
130     0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F,
131     0x0650, 0x0651, 0x0652, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
132     0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
133 };
134
135 /* ISO 8859-7:1987 (Latin/Greek) */
136 static wchar_t iso_8859_7[] = {
137     0x00A0, 0x2018, 0x2019, 0x00A3, 0xFFFD, 0xFFFD, 0x00A6, 0x00A7,
138     0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015,
139     0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7,
140     0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
141     0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
142     0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
143     0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
144     0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
145     0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
146     0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
147     0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
148     0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD
149 };
150
151 /* ISO/IEC 8859-8:1999 (Latin/Hebrew) */
152 static wchar_t iso_8859_8[] = {
153     0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
154     0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
155     0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
156     0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xFFFD,
157     0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
158     0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
159     0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
160     0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2017,
161     0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
162     0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
163     0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
164     0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD
165 };
166
167 /* ISO/IEC 8859-9:1999 (Latin-5, "Turkish") */
168 static wchar_t iso_8859_9[] = {
169     0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
170     0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
171     0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
172     0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
173     0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
174     0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
175     0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
176     0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
177     0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
178     0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
179     0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
180     0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
181 };
182
183 /* ISO 8859-10:1993? (Latin-6, "Nordic" [Sami, Inuit, Icelandic]) */
184 /* Translation table from RDB. unicode.org (ISO/IEC 8859-10:1998) has
185  * U+2015 (HORIZONTAL BAR) at codepoint 0xBD instead
186  * (U+2014 is EM DASH). -- jtn */
187 static 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, 0x2014, 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 8859-11:1997" ("Thai", "TIS620") */
203 /* From RDB -- ISO and unicode.org disclaim all knowledge of this one.
204  * Maybe still in draft. --jtn */
205 static 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 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 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 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 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 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 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 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 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     wchar_t *cp_table;
373 };
374
375 static 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:1997 (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_tables(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 void lpage_send(int codepage, char *buf, int len, int interactive)
601 {
602     static wchar_t *widebuffer = 0;
603     static int widesize = 0;
604     int wclen;
605
606     if (codepage < 0) {
607         ldisc_send(buf, len, interactive);
608         return;
609     }
610
611     if (len > widesize) {
612         sfree(widebuffer);
613         widebuffer = smalloc(len * 2 * sizeof(wchar_t));
614         widesize = len * 2;
615     }
616
617     wclen = mb_to_wc(codepage, 0, buf, len, widebuffer, widesize);
618     luni_send(widebuffer, wclen, interactive);
619 }
620
621 void luni_send(wchar_t * widebuf, int len, int interactive)
622 {
623     static char *linebuffer = 0;
624     static int linesize = 0;
625     int ratio = (in_utf)?3:1;
626     int i;
627     char *p;
628
629     if (len * ratio > linesize) {
630         sfree(linebuffer);
631         linebuffer = smalloc(len * ratio * 2 * sizeof(wchar_t));
632         linesize = len * ratio * 2;
633     }
634
635     if (in_utf) {
636         /* UTF is a simple algorithm */
637         for (p = linebuffer, i = 0; i < len; i++) {
638             wchar_t ch = widebuf[i];
639             /* Windows wchar_t is UTF-16 */
640             if ((ch&0xF800) == 0xD800) ch = '.';
641
642             if (ch < 0x80) {
643                 *p++ = (char) (ch);
644             } else if (ch < 0x800) {
645                 *p++ = (0xC0 | (ch >> 6));
646                 *p++ = (0x80 | (ch & 0x3F));
647             } else {
648                 *p++ = (0xE0 | (ch >> 12));
649                 *p++ = (0x80 | ((ch >> 6) & 0x3F));
650                 *p++ = (0x80 | (ch & 0x3F));
651             }
652         }
653     } else if (!uni_tbl) {
654         int rv;
655         rv = wc_to_mb(line_codepage, 0, widebuf, len,
656                       linebuffer, linesize, NULL, NULL);
657         if (rv >= 0)
658             p = linebuffer + rv;
659         else
660             p = linebuffer;
661     } else {
662         /* Others are a lookup in an array */
663         for (p = linebuffer, i = 0; i < len; i++) {
664             wchar_t ch = widebuf[i];
665             int by;
666             char *p1;
667             if (uni_tbl && (p1 = uni_tbl[(ch >> 8) & 0xFF])
668                 && (by = p1[ch & 0xFF]))
669                 *p++ = by;
670             else if (ch < 0x80)
671                 *p++ = (char) ch;
672 #if 1
673             else
674                 *p++ = '.';
675 #endif
676         }
677     }
678     if (p > linebuffer)
679         ldisc_send(linebuffer, p - linebuffer, interactive);
680 }
681
682 wchar_t xlat_uskbd2cyrllic(int ch)
683 {
684     static wchar_t cyrtab[] = {
685             0,      1,       2,      3,      4,      5,      6,      7,
686             8,      9,      10,     11,     12,     13,     14,     15,
687             16,     17,     18,     19,     20,     21,     22,     23,
688             24,     25,     26,     27,     28,     29,     30,     31,
689             32,     33, 0x042d,     35,     36,     37,     38, 0x044d,
690             40,     41,     42, 0x0406, 0x0431, 0x0454, 0x044e, 0x002e,
691             48,     49,     50,     51,     52,     53,     54,     55,
692             56,     57, 0x0416, 0x0436, 0x0411, 0x0456, 0x042e, 0x002c,
693             64, 0x0424, 0x0418, 0x0421, 0x0412, 0x0423, 0x0410, 0x041f,
694         0x0420, 0x0428, 0x041e, 0x041b, 0x0414, 0x042c, 0x0422, 0x0429,
695         0x0417, 0x0419, 0x041a, 0x042b, 0x0415, 0x0413, 0x041c, 0x0426,
696         0x0427, 0x041d, 0x042f, 0x0445, 0x0457, 0x044a,     94, 0x0404,
697             96, 0x0444, 0x0438, 0x0441, 0x0432, 0x0443, 0x0430, 0x043f,
698         0x0440, 0x0448, 0x043e, 0x043b, 0x0434, 0x044c, 0x0442, 0x0449,
699         0x0437, 0x0439, 0x043a, 0x044b, 0x0435, 0x0433, 0x043c, 0x0446,
700         0x0447, 0x043d, 0x044f, 0x0425, 0x0407, 0x042a,    126,    127
701        };
702     return cyrtab[ch&0x7F];
703 }
704
705 int check_compose(int first, int second)
706 {
707
708     static struct {
709         char first, second;
710         wchar_t composed;
711     } composetbl[] = {
712         {
713         0x2b, 0x2b, 0x0023}, {
714         0x41, 0x41, 0x0040}, {
715         0x28, 0x28, 0x005b}, {
716         0x2f, 0x2f, 0x005c}, {
717         0x29, 0x29, 0x005d}, {
718         0x28, 0x2d, 0x007b}, {
719         0x2d, 0x29, 0x007d}, {
720         0x2f, 0x5e, 0x007c}, {
721         0x21, 0x21, 0x00a1}, {
722         0x43, 0x2f, 0x00a2}, {
723         0x43, 0x7c, 0x00a2}, {
724         0x4c, 0x2d, 0x00a3}, {
725         0x4c, 0x3d, 0x20a4}, {
726         0x58, 0x4f, 0x00a4}, {
727         0x58, 0x30, 0x00a4}, {
728         0x59, 0x2d, 0x00a5}, {
729         0x59, 0x3d, 0x00a5}, {
730         0x7c, 0x7c, 0x00a6}, {
731         0x53, 0x4f, 0x00a7}, {
732         0x53, 0x21, 0x00a7}, {
733         0x53, 0x30, 0x00a7}, {
734         0x22, 0x22, 0x00a8}, {
735         0x43, 0x4f, 0x00a9}, {
736         0x43, 0x30, 0x00a9}, {
737         0x41, 0x5f, 0x00aa}, {
738         0x3c, 0x3c, 0x00ab}, {
739         0x2c, 0x2d, 0x00ac}, {
740         0x2d, 0x2d, 0x00ad}, {
741         0x52, 0x4f, 0x00ae}, {
742         0x2d, 0x5e, 0x00af}, {
743         0x30, 0x5e, 0x00b0}, {
744         0x2b, 0x2d, 0x00b1}, {
745         0x32, 0x5e, 0x00b2}, {
746         0x33, 0x5e, 0x00b3}, {
747         0x27, 0x27, 0x00b4}, {
748         0x2f, 0x55, 0x00b5}, {
749         0x50, 0x21, 0x00b6}, {
750         0x2e, 0x5e, 0x00b7}, {
751         0x2c, 0x2c, 0x00b8}, {
752         0x31, 0x5e, 0x00b9}, {
753         0x4f, 0x5f, 0x00ba}, {
754         0x3e, 0x3e, 0x00bb}, {
755         0x31, 0x34, 0x00bc}, {
756         0x31, 0x32, 0x00bd}, {
757         0x33, 0x34, 0x00be}, {
758         0x3f, 0x3f, 0x00bf}, {
759         0x60, 0x41, 0x00c0}, {
760         0x27, 0x41, 0x00c1}, {
761         0x5e, 0x41, 0x00c2}, {
762         0x7e, 0x41, 0x00c3}, {
763         0x22, 0x41, 0x00c4}, {
764         0x2a, 0x41, 0x00c5}, {
765         0x41, 0x45, 0x00c6}, {
766         0x2c, 0x43, 0x00c7}, {
767         0x60, 0x45, 0x00c8}, {
768         0x27, 0x45, 0x00c9}, {
769         0x5e, 0x45, 0x00ca}, {
770         0x22, 0x45, 0x00cb}, {
771         0x60, 0x49, 0x00cc}, {
772         0x27, 0x49, 0x00cd}, {
773         0x5e, 0x49, 0x00ce}, {
774         0x22, 0x49, 0x00cf}, {
775         0x2d, 0x44, 0x00d0}, {
776         0x7e, 0x4e, 0x00d1}, {
777         0x60, 0x4f, 0x00d2}, {
778         0x27, 0x4f, 0x00d3}, {
779         0x5e, 0x4f, 0x00d4}, {
780         0x7e, 0x4f, 0x00d5}, {
781         0x22, 0x4f, 0x00d6}, {
782         0x58, 0x58, 0x00d7}, {
783         0x2f, 0x4f, 0x00d8}, {
784         0x60, 0x55, 0x00d9}, {
785         0x27, 0x55, 0x00da}, {
786         0x5e, 0x55, 0x00db}, {
787         0x22, 0x55, 0x00dc}, {
788         0x27, 0x59, 0x00dd}, {
789         0x48, 0x54, 0x00de}, {
790         0x73, 0x73, 0x00df}, {
791         0x60, 0x61, 0x00e0}, {
792         0x27, 0x61, 0x00e1}, {
793         0x5e, 0x61, 0x00e2}, {
794         0x7e, 0x61, 0x00e3}, {
795         0x22, 0x61, 0x00e4}, {
796         0x2a, 0x61, 0x00e5}, {
797         0x61, 0x65, 0x00e6}, {
798         0x2c, 0x63, 0x00e7}, {
799         0x60, 0x65, 0x00e8}, {
800         0x27, 0x65, 0x00e9}, {
801         0x5e, 0x65, 0x00ea}, {
802         0x22, 0x65, 0x00eb}, {
803         0x60, 0x69, 0x00ec}, {
804         0x27, 0x69, 0x00ed}, {
805         0x5e, 0x69, 0x00ee}, {
806         0x22, 0x69, 0x00ef}, {
807         0x2d, 0x64, 0x00f0}, {
808         0x7e, 0x6e, 0x00f1}, {
809         0x60, 0x6f, 0x00f2}, {
810         0x27, 0x6f, 0x00f3}, {
811         0x5e, 0x6f, 0x00f4}, {
812         0x7e, 0x6f, 0x00f5}, {
813         0x22, 0x6f, 0x00f6}, {
814         0x3a, 0x2d, 0x00f7}, {
815         0x6f, 0x2f, 0x00f8}, {
816         0x60, 0x75, 0x00f9}, {
817         0x27, 0x75, 0x00fa}, {
818         0x5e, 0x75, 0x00fb}, {
819         0x22, 0x75, 0x00fc}, {
820         0x27, 0x79, 0x00fd}, {
821         0x68, 0x74, 0x00fe}, {
822         0x22, 0x79, 0x00ff},
823             /* Unicode extras. */
824         {
825         0x6f, 0x65, 0x0153}, {
826         0x4f, 0x45, 0x0152},
827             /* Compose pairs from UCS */
828         {
829         0x41, 0x2D, 0x0100}, {
830         0x61, 0x2D, 0x0101}, {
831         0x43, 0x27, 0x0106}, {
832         0x63, 0x27, 0x0107}, {
833         0x43, 0x5E, 0x0108}, {
834         0x63, 0x5E, 0x0109}, {
835         0x45, 0x2D, 0x0112}, {
836         0x65, 0x2D, 0x0113}, {
837         0x47, 0x5E, 0x011C}, {
838         0x67, 0x5E, 0x011D}, {
839         0x47, 0x2C, 0x0122}, {
840         0x67, 0x2C, 0x0123}, {
841         0x48, 0x5E, 0x0124}, {
842         0x68, 0x5E, 0x0125}, {
843         0x49, 0x7E, 0x0128}, {
844         0x69, 0x7E, 0x0129}, {
845         0x49, 0x2D, 0x012A}, {
846         0x69, 0x2D, 0x012B}, {
847         0x4A, 0x5E, 0x0134}, {
848         0x6A, 0x5E, 0x0135}, {
849         0x4B, 0x2C, 0x0136}, {
850         0x6B, 0x2C, 0x0137}, {
851         0x4C, 0x27, 0x0139}, {
852         0x6C, 0x27, 0x013A}, {
853         0x4C, 0x2C, 0x013B}, {
854         0x6C, 0x2C, 0x013C}, {
855         0x4E, 0x27, 0x0143}, {
856         0x6E, 0x27, 0x0144}, {
857         0x4E, 0x2C, 0x0145}, {
858         0x6E, 0x2C, 0x0146}, {
859         0x4F, 0x2D, 0x014C}, {
860         0x6F, 0x2D, 0x014D}, {
861         0x52, 0x27, 0x0154}, {
862         0x72, 0x27, 0x0155}, {
863         0x52, 0x2C, 0x0156}, {
864         0x72, 0x2C, 0x0157}, {
865         0x53, 0x27, 0x015A}, {
866         0x73, 0x27, 0x015B}, {
867         0x53, 0x5E, 0x015C}, {
868         0x73, 0x5E, 0x015D}, {
869         0x53, 0x2C, 0x015E}, {
870         0x73, 0x2C, 0x015F}, {
871         0x54, 0x2C, 0x0162}, {
872         0x74, 0x2C, 0x0163}, {
873         0x55, 0x7E, 0x0168}, {
874         0x75, 0x7E, 0x0169}, {
875         0x55, 0x2D, 0x016A}, {
876         0x75, 0x2D, 0x016B}, {
877         0x55, 0x2A, 0x016E}, {
878         0x75, 0x2A, 0x016F}, {
879         0x57, 0x5E, 0x0174}, {
880         0x77, 0x5E, 0x0175}, {
881         0x59, 0x5E, 0x0176}, {
882         0x79, 0x5E, 0x0177}, {
883         0x59, 0x22, 0x0178}, {
884         0x5A, 0x27, 0x0179}, {
885         0x7A, 0x27, 0x017A}, {
886         0x47, 0x27, 0x01F4}, {
887         0x67, 0x27, 0x01F5}, {
888         0x4E, 0x60, 0x01F8}, {
889         0x6E, 0x60, 0x01F9}, {
890         0x45, 0x2C, 0x0228}, {
891         0x65, 0x2C, 0x0229}, {
892         0x59, 0x2D, 0x0232}, {
893         0x79, 0x2D, 0x0233}, {
894         0x44, 0x2C, 0x1E10}, {
895         0x64, 0x2C, 0x1E11}, {
896         0x47, 0x2D, 0x1E20}, {
897         0x67, 0x2D, 0x1E21}, {
898         0x48, 0x22, 0x1E26}, {
899         0x68, 0x22, 0x1E27}, {
900         0x48, 0x2C, 0x1E28}, {
901         0x68, 0x2C, 0x1E29}, {
902         0x4B, 0x27, 0x1E30}, {
903         0x6B, 0x27, 0x1E31}, {
904         0x4D, 0x27, 0x1E3E}, {
905         0x6D, 0x27, 0x1E3F}, {
906         0x50, 0x27, 0x1E54}, {
907         0x70, 0x27, 0x1E55}, {
908         0x56, 0x7E, 0x1E7C}, {
909         0x76, 0x7E, 0x1E7D}, {
910         0x57, 0x60, 0x1E80}, {
911         0x77, 0x60, 0x1E81}, {
912         0x57, 0x27, 0x1E82}, {
913         0x77, 0x27, 0x1E83}, {
914         0x57, 0x22, 0x1E84}, {
915         0x77, 0x22, 0x1E85}, {
916         0x58, 0x22, 0x1E8C}, {
917         0x78, 0x22, 0x1E8D}, {
918         0x5A, 0x5E, 0x1E90}, {
919         0x7A, 0x5E, 0x1E91}, {
920         0x74, 0x22, 0x1E97}, {
921         0x77, 0x2A, 0x1E98}, {
922         0x79, 0x2A, 0x1E99}, {
923         0x45, 0x7E, 0x1EBC}, {
924         0x65, 0x7E, 0x1EBD}, {
925         0x59, 0x60, 0x1EF2}, {
926         0x79, 0x60, 0x1EF3}, {
927         0x59, 0x7E, 0x1EF8}, {
928         0x79, 0x7E, 0x1EF9},
929             /* Compatible/possibles from UCS */
930         {
931         0x49, 0x4A, 0x0132}, {
932         0x69, 0x6A, 0x0133}, {
933         0x4C, 0x4A, 0x01C7}, {
934         0x4C, 0x6A, 0x01C8}, {
935         0x6C, 0x6A, 0x01C9}, {
936         0x4E, 0x4A, 0x01CA}, {
937         0x4E, 0x6A, 0x01CB}, {
938         0x6E, 0x6A, 0x01CC}, {
939         0x44, 0x5A, 0x01F1}, {
940         0x44, 0x7A, 0x01F2}, {
941         0x64, 0x7A, 0x01F3}, {
942         0x2E, 0x2E, 0x2025}, {
943         0x21, 0x21, 0x203C}, {
944         0x3F, 0x21, 0x2048}, {
945         0x21, 0x3F, 0x2049}, {
946         0x52, 0x73, 0x20A8}, {
947         0x4E, 0x6F, 0x2116}, {
948         0x53, 0x4D, 0x2120}, {
949         0x54, 0x4D, 0x2122}, {
950         0x49, 0x49, 0x2161}, {
951         0x49, 0x56, 0x2163}, {
952         0x56, 0x49, 0x2165}, {
953         0x49, 0x58, 0x2168}, {
954         0x58, 0x49, 0x216A}, {
955         0x69, 0x69, 0x2171}, {
956         0x69, 0x76, 0x2173}, {
957         0x76, 0x69, 0x2175}, {
958         0x69, 0x78, 0x2178}, {
959         0x78, 0x69, 0x217A}, {
960         0x31, 0x30, 0x2469}, {
961         0x31, 0x31, 0x246A}, {
962         0x31, 0x32, 0x246B}, {
963         0x31, 0x33, 0x246C}, {
964         0x31, 0x34, 0x246D}, {
965         0x31, 0x35, 0x246E}, {
966         0x31, 0x36, 0x246F}, {
967         0x31, 0x37, 0x2470}, {
968         0x31, 0x38, 0x2471}, {
969         0x31, 0x39, 0x2472}, {
970         0x32, 0x30, 0x2473}, {
971         0x31, 0x2E, 0x2488}, {
972         0x32, 0x2E, 0x2489}, {
973         0x33, 0x2E, 0x248A}, {
974         0x34, 0x2E, 0x248B}, {
975         0x35, 0x2E, 0x248C}, {
976         0x36, 0x2E, 0x248D}, {
977         0x37, 0x2E, 0x248E}, {
978         0x38, 0x2E, 0x248F}, {
979         0x39, 0x2E, 0x2490}, {
980         0x64, 0x61, 0x3372}, {
981         0x41, 0x55, 0x3373}, {
982         0x6F, 0x56, 0x3375}, {
983         0x70, 0x63, 0x3376}, {
984         0x70, 0x41, 0x3380}, {
985         0x6E, 0x41, 0x3381}, {
986         0x6D, 0x41, 0x3383}, {
987         0x6B, 0x41, 0x3384}, {
988         0x4B, 0x42, 0x3385}, {
989         0x4D, 0x42, 0x3386}, {
990         0x47, 0x42, 0x3387}, {
991         0x70, 0x46, 0x338A}, {
992         0x6E, 0x46, 0x338B}, {
993         0x6D, 0x67, 0x338E}, {
994         0x6B, 0x67, 0x338F}, {
995         0x48, 0x7A, 0x3390}, {
996         0x66, 0x6D, 0x3399}, {
997         0x6E, 0x6D, 0x339A}, {
998         0x6D, 0x6D, 0x339C}, {
999         0x63, 0x6D, 0x339D}, {
1000         0x6B, 0x6D, 0x339E}, {
1001         0x50, 0x61, 0x33A9}, {
1002         0x70, 0x73, 0x33B0}, {
1003         0x6E, 0x73, 0x33B1}, {
1004         0x6D, 0x73, 0x33B3}, {
1005         0x70, 0x56, 0x33B4}, {
1006         0x6E, 0x56, 0x33B5}, {
1007         0x6D, 0x56, 0x33B7}, {
1008         0x6B, 0x56, 0x33B8}, {
1009         0x4D, 0x56, 0x33B9}, {
1010         0x70, 0x57, 0x33BA}, {
1011         0x6E, 0x57, 0x33BB}, {
1012         0x6D, 0x57, 0x33BD}, {
1013         0x6B, 0x57, 0x33BE}, {
1014         0x4D, 0x57, 0x33BF}, {
1015         0x42, 0x71, 0x33C3}, {
1016         0x63, 0x63, 0x33C4}, {
1017         0x63, 0x64, 0x33C5}, {
1018         0x64, 0x42, 0x33C8}, {
1019         0x47, 0x79, 0x33C9}, {
1020         0x68, 0x61, 0x33CA}, {
1021         0x48, 0x50, 0x33CB}, {
1022         0x69, 0x6E, 0x33CC}, {
1023         0x4B, 0x4B, 0x33CD}, {
1024         0x4B, 0x4D, 0x33CE}, {
1025         0x6B, 0x74, 0x33CF}, {
1026         0x6C, 0x6D, 0x33D0}, {
1027         0x6C, 0x6E, 0x33D1}, {
1028         0x6C, 0x78, 0x33D3}, {
1029         0x6D, 0x62, 0x33D4}, {
1030         0x50, 0x48, 0x33D7}, {
1031         0x50, 0x52, 0x33DA}, {
1032         0x73, 0x72, 0x33DB}, {
1033         0x53, 0x76, 0x33DC}, {
1034         0x57, 0x62, 0x33DD}, {
1035         0x66, 0x66, 0xFB00}, {
1036         0x66, 0x69, 0xFB01}, {
1037         0x66, 0x6C, 0xFB02}, {
1038         0x73, 0x74, 0xFB06}, {
1039         0, 0, 0}
1040     }, *c;
1041
1042     static int recurse = 0;
1043     int nc = -1;
1044
1045     for (c = composetbl; c->first; c++) {
1046         if (c->first == first && c->second == second)
1047             return c->composed;
1048     }
1049
1050     if (recurse == 0) {
1051         recurse = 1;
1052         nc = check_compose(second, first);
1053         if (nc == -1)
1054             nc = check_compose(toupper(first), toupper(second));
1055         if (nc == -1)
1056             nc = check_compose(toupper(second), toupper(first));
1057         recurse = 0;
1058     }
1059     return nc;
1060 }
1061
1062 int decode_codepage(char *cp_name)
1063 {
1064     char *s, *d;
1065     struct cp_list_item *cpi;
1066     int codepage = -1;
1067     CPINFO cpinfo;
1068
1069     if (!*cp_name) {
1070         /*
1071          * Here we select a plausible default code page based on
1072          * the locale the user is in. We wish to select an ISO code
1073          * page or appropriate local default _rather_ than go with
1074          * the Win125* series, because it's more important to have
1075          * CSI and friends enabled by default than the ghastly
1076          * Windows extra quote characters, and because it's more
1077          * likely the user is connecting to a remote server that
1078          * does something Unixy or VMSy and hence standards-
1079          * compliant than that they're connecting back to a Windows
1080          * box using horrible nonstandard charsets.
1081          * 
1082          * Accordingly, Robert de Bath suggests a method for
1083          * picking a default character set that runs as follows:
1084          * first call GetACP to get the system's ANSI code page
1085          * identifier, and translate as follows:
1086          * 
1087          * 1250 -> ISO 8859-2
1088          * 1251 -> KOI8-U
1089          * 1252 -> ISO 8859-1
1090          * 1253 -> ISO 8859-7
1091          * 1254 -> ISO 8859-9
1092          * 1255 -> ISO 8859-8
1093          * 1256 -> ISO 8859-6
1094          * 1257 -> ISO 8859-4
1095          * 
1096          * and for anything else, choose direct-to-font.
1097          */
1098         int cp = GetACP();
1099         switch (cp) {
1100           case 1250: cp_name = "ISO-8859-2"; break;
1101           case 1251: cp_name = "KOI8-U"; break;
1102           case 1252: cp_name = "ISO-8859-1"; break;
1103           case 1253: cp_name = "ISO-8859-7"; break;
1104           case 1254: cp_name = "ISO-8859-9"; break;
1105           case 1255: cp_name = "ISO-8859-8"; break;
1106           case 1256: cp_name = "ISO-8859-6"; break;
1107           case 1257: cp_name = "ISO-8859-4"; break;
1108             /* default: leave it blank, which will select -1, direct->font */
1109         }
1110     }
1111
1112     if (cp_name && *cp_name)
1113         for (cpi = cp_list; cpi->name; cpi++) {
1114             s = cp_name;
1115             d = cpi->name;
1116             for (;;) {
1117                 while (*s && !isalnum(*s) && *s != ':')
1118                     s++;
1119                 while (*d && !isalnum(*d) && *d != ':')
1120                     d++;
1121                 if (*s == 0) {
1122                     codepage = cpi->codepage;
1123                     if (codepage == CP_UTF8)
1124                         goto break_break;
1125                     if (codepage == -1)
1126                         return codepage;
1127                     if (codepage == 0) {
1128                         codepage = 65536 + (cpi - cp_list);
1129                         goto break_break;
1130                     }
1131
1132                     if (GetCPInfo(codepage, &cpinfo) != 0)
1133                         goto break_break;
1134                 }
1135                 if (tolower(*s++) != tolower(*d++))
1136                     break;
1137             }
1138         }
1139
1140     if (cp_name && *cp_name) {
1141         d = cp_name;
1142         if (tolower(d[0]) == 'c' && tolower(d[1]) == 'p')
1143             d += 2;
1144         if (tolower(d[0]) == 'i' && tolower(d[1]) == 'b'
1145             && tolower(d[1]) == 'm')
1146             d += 3;
1147         for (s = d; *s >= '0' && *s <= '9'; s++);
1148         if (*s == 0 && s != d)
1149             codepage = atoi(d);        /* CP999 or IBM999 */
1150
1151         if (codepage == CP_ACP)
1152             codepage = GetACP();
1153         if (codepage == CP_OEMCP)
1154             codepage = GetOEMCP();
1155         if (codepage > 65535)
1156             codepage = -2;
1157     }
1158
1159   break_break:;
1160     if (codepage != -1) {
1161         if (codepage != CP_UTF8 && codepage < 65536) {
1162             if (GetCPInfo(codepage, &cpinfo) == 0) {
1163                 codepage = -2;
1164             } else if (cpinfo.MaxCharSize > 1)
1165                 codepage = -3;
1166         }
1167     }
1168     if (codepage == -1 && *cp_name)
1169         codepage = -2;
1170     return codepage;
1171 }
1172
1173 char *cp_name(int codepage)
1174 {
1175     struct cp_list_item *cpi, *cpno;
1176     static char buf[32];
1177
1178     if (codepage == -1) {
1179         sprintf(buf, "Use font encoding");
1180         return buf;
1181     }
1182
1183     if (codepage > 0 && codepage < 65536)
1184         sprintf(buf, "CP%03d", codepage);
1185     else
1186         *buf = 0;
1187
1188     if (codepage >= 65536) {
1189         cpno = 0;
1190         for (cpi = cp_list; cpi->name; cpi++)
1191             if (cpi == cp_list + (codepage - 65536)) {
1192                 cpno = cpi;
1193                 break;
1194             }
1195         if (cpno)
1196             for (cpi = cp_list; cpi->name; cpi++) {
1197                 if (cpno->cp_table == cpi->cp_table)
1198                     return cpi->name;
1199             }
1200     } else {
1201         for (cpi = cp_list; cpi->name; cpi++) {
1202             if (codepage == cpi->codepage)
1203                 return cpi->name;
1204         }
1205     }
1206     return buf;
1207 }
1208
1209 /*
1210  * Return the nth code page in the list, for use in the GUI
1211  * configurer.
1212  */
1213 char *cp_enumerate(int index)
1214 {
1215     if (index < 0 || index >= lenof(cp_list))
1216         return NULL;
1217     return cp_list[index].name;
1218 }
1219
1220 void get_unitab(int codepage, wchar_t * unitab, int ftype)
1221 {
1222     char tbuf[4];
1223     int i, max = 256, flg = MB_ERR_INVALID_CHARS;
1224
1225     if (ftype)
1226         flg |= MB_USEGLYPHCHARS;
1227     if (ftype == 2)
1228         max = 128;
1229
1230     if (codepage == CP_UTF8) {
1231         for (i = 0; i < max; i++)
1232             unitab[i] = i;
1233         return;
1234     }
1235
1236     if (codepage == CP_ACP)
1237         codepage = GetACP();
1238     else if (codepage == CP_OEMCP)
1239         codepage = GetOEMCP();
1240
1241     if (codepage > 0 && codepage < 65536) {
1242         for (i = 0; i < max; i++) {
1243             tbuf[0] = i;
1244
1245             if (mb_to_wc(codepage, flg, tbuf, 1, unitab + i, 1)
1246                 != 1)
1247                 unitab[i] = 0xFFFD;
1248         }
1249     } else {
1250         int j = 256 - cp_list[codepage & 0xFFFF].cp_size;
1251         for (i = 0; i < max; i++)
1252             unitab[i] = i;
1253         for (i = j; i < max; i++)
1254             unitab[i] = cp_list[codepage & 0xFFFF].cp_table[i - j];
1255     }
1256 }