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