charsets.c revision e0a2b6df
1/* $XTermId: charsets.c,v 1.67 2013/12/01 16:38:13 tom Exp $ */
2
3/*
4 * Copyright 1998-2011,2013 by Thomas E. Dickey
5 *
6 *                         All Rights Reserved
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the
10 * "Software"), to deal in the Software without restriction, including
11 * without limitation the rights to use, copy, modify, merge, publish,
12 * distribute, sublicense, and/or sell copies of the Software, and to
13 * permit persons to whom the Software is furnished to do so, subject to
14 * the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Except as contained in this notice, the name(s) of the above copyright
28 * holders shall not be used in advertising or otherwise to promote the
29 * sale, use or other dealings in this Software without prior written
30 * authorization.
31 *
32 */
33
34#include <xterm.h>
35#include <data.h>
36#include <fontutils.h>
37
38#include <X11/keysym.h>
39
40/*
41 * This module performs translation as needed to support the DEC VT220 national
42 * replacement character sets.  We assume that xterm's font is based on the ISO
43 * 8859-1 (Latin 1) character set, which is almost the same as the DEC
44 * multinational character set.  Glyph positions 0-31 have to be the DEC
45 * graphic characters, though.
46 *
47 * References:
48 *	"VT220 Programmer Pocket Guide" EK-VT220-HR-002 (2nd ed., 1984), which
49 *		contains character charts for the national character sets.
50 *	"VT330/VT340 Programmer Reference Manual Volume 1: Text Programming"
51 *		EK-VT3XX-TP-001 (1st ed, 1987), which contains a table (2-1)
52 *		listing the glyphs which are mapped from the multinational
53 *		character set to the national character set.
54 *
55 * The latter reference, though easier to read, has a few errors and omissions.
56 */
57
58#define map_NRCS_Dutch(code) \
59	switch (code) { \
60	    MAP(0x23, XK_sterling); \
61	    MAP(0x40, XK_threequarters); \
62	    UNI(0x5b, 0x0133); /* ij ligature */ \
63	    MAP(0x5c, XK_onehalf); \
64	    MAP(0x5d, XK_bar); \
65	    MAP(0x7b, XK_diaeresis); \
66	    UNI(0x7c, 0x0192); /* florin */ \
67	    MAP(0x7d, XK_onequarter); \
68	    MAP(0x7e, XK_acute); \
69	}
70
71#define map_NRCS_Finnish(code) \
72	switch (code) { \
73	    MAP(0x5b, XK_Adiaeresis); \
74	    MAP(0x5c, XK_Odiaeresis); \
75	    MAP(0x5d, XK_Aring); \
76	    MAP(0x5e, XK_Udiaeresis); \
77	    MAP(0x60, XK_eacute); \
78	    MAP(0x7b, XK_adiaeresis); \
79	    MAP(0x7c, XK_odiaeresis); \
80	    MAP(0x7d, XK_aring); \
81	    MAP(0x7e, XK_udiaeresis); \
82	}
83
84#define map_NRCS_French(code) \
85	switch (code) { \
86	    MAP(0x23, XK_sterling); \
87	    MAP(0x40, XK_agrave); \
88	    MAP(0x5b, XK_degree); \
89	    MAP(0x5c, XK_ccedilla); \
90	    MAP(0x5d, XK_section); \
91	    MAP(0x7b, XK_eacute); \
92	    MAP(0x7c, XK_ugrave); \
93	    MAP(0x7d, XK_egrave); \
94	    MAP(0x7e, XK_diaeresis); \
95	}
96
97#define map_NRCS_French_Canadian(code) \
98	switch (code) { \
99	    MAP(0x40, XK_agrave); \
100	    MAP(0x5b, XK_acircumflex); \
101	    MAP(0x5c, XK_ccedilla); \
102	    MAP(0x5d, XK_ecircumflex); \
103	    MAP(0x5e, XK_icircumflex); \
104	    MAP(0x60, XK_ocircumflex); \
105	    MAP(0x7b, XK_eacute); \
106	    MAP(0x7c, XK_ugrave); \
107	    MAP(0x7d, XK_egrave); \
108	    MAP(0x7e, XK_ucircumflex); \
109	}
110
111#define map_NRCS_German(code) \
112	switch (code) { \
113	    MAP(0x40, XK_section); \
114	    MAP(0x5b, XK_Adiaeresis); \
115	    MAP(0x5c, XK_Odiaeresis); \
116	    MAP(0x5d, XK_Udiaeresis); \
117	    MAP(0x7b, XK_adiaeresis); \
118	    MAP(0x7c, XK_odiaeresis); \
119	    MAP(0x7d, XK_udiaeresis); \
120	    MAP(0x7e, XK_ssharp); \
121	}
122
123#define map_NRCS_Italian(code) \
124	switch (code) { \
125	    MAP(0x23, XK_sterling); \
126	    MAP(0x40, XK_section); \
127	    MAP(0x5b, XK_degree); \
128	    MAP(0x5c, XK_ccedilla); \
129	    MAP(0x5d, XK_eacute); \
130	    MAP(0x60, XK_ugrave); \
131	    MAP(0x7b, XK_agrave); \
132	    MAP(0x7c, XK_ograve); \
133	    MAP(0x7d, XK_egrave); \
134	    MAP(0x7e, XK_igrave); \
135	}
136
137#define map_NRCS_Norwegian_Danish(code) \
138	switch (code) { \
139	    MAP(0x40, XK_Adiaeresis); \
140	    MAP(0x5b, XK_AE); \
141	    MAP(0x5c, XK_Ooblique); \
142	    MAP(0x5d, XK_Aring); \
143	    MAP(0x5e, XK_Udiaeresis); \
144	    MAP(0x60, XK_adiaeresis); \
145	    MAP(0x7b, XK_ae); \
146	    MAP(0x7c, XK_oslash); \
147	    MAP(0x7d, XK_aring); \
148	    MAP(0x7e, XK_udiaeresis); \
149	}
150
151#define map_NRCS_Portuguese(code) \
152	switch (code) { \
153	    MAP(0x5b, XK_Atilde); \
154	    MAP(0x5c, XK_Ccedilla); \
155	    MAP(0x5d, XK_Otilde); \
156	    MAP(0x7b, XK_atilde); \
157	    MAP(0x7c, XK_ccedilla); \
158	    MAP(0x7d, XK_otilde); \
159	}
160
161#define map_NRCS_Spanish(code) \
162	switch (code) { \
163	    MAP(0x23, XK_sterling); \
164	    MAP(0x40, XK_section); \
165	    MAP(0x5b, XK_exclamdown); \
166	    MAP(0x5c, XK_Ntilde); \
167	    MAP(0x5d, XK_questiondown); \
168	    MAP(0x7b, XK_degree); \
169	    MAP(0x7c, XK_ntilde); \
170	    MAP(0x7d, XK_ccedilla); \
171	}
172
173#define map_NRCS_Swedish(code) \
174	switch (code) { \
175	    MAP(0x40, XK_Eacute); \
176	    MAP(0x5b, XK_Adiaeresis); \
177	    MAP(0x5c, XK_Odiaeresis); \
178	    MAP(0x5d, XK_Aring); \
179	    MAP(0x5e, XK_Udiaeresis); \
180	    MAP(0x60, XK_eacute); \
181	    MAP(0x7b, XK_adiaeresis); \
182	    MAP(0x7c, XK_odiaeresis); \
183	    MAP(0x7d, XK_aring); \
184	    MAP(0x7e, XK_udiaeresis); \
185	}
186
187#define map_NRCS_Swiss(code) \
188	switch (code) { \
189	    MAP(0x23, XK_ugrave); \
190	    MAP(0x40, XK_agrave); \
191	    MAP(0x5b, XK_eacute); \
192	    MAP(0x5c, XK_ccedilla); \
193	    MAP(0x5d, XK_ecircumflex); \
194	    MAP(0x5e, XK_icircumflex); \
195	    MAP(0x5f, XK_egrave); \
196	    MAP(0x60, XK_ocircumflex); \
197	    MAP(0x7b, XK_adiaeresis); \
198	    MAP(0x7c, XK_odiaeresis); \
199	    MAP(0x7d, XK_udiaeresis); \
200	    MAP(0x7e, XK_ucircumflex); \
201	}
202
203/*
204 * Unlike NRCS, which splices a few characters onto ASCII, the supplementary
205 * character sets are complete, normally mapped to GR.  Most of these mappings
206 * rely upon glyphs not found in ISO-8859-1.  We can display most of those
207 * using Unicode, thereby supporting specialized applications that use SCS
208 * with luit, subject to the limitation that select/paste will give meaningless
209 * results in terms of the application which uses these mappings.
210 *
211 * Since the VT320, etc, use only 8-bit encodings, there is no plausible
212 * argument to be made that these mappings "use" UTF-8, even though there is
213 * a hidden step in the terminal emulator which relies upon UTF-8.
214 */
215#define map_SCS_DEC_Supp(code,dft) \
216	switch (code) { \
217	    XXX(0x24, 0x2e2e); \
218	    XXX(0x26, 0x2e2e); \
219	    XXX(0x2c, 0x2e2e); \
220	    XXX(0x2d, 0x2e2e); \
221	    XXX(0x2e, 0x2e2e); \
222	    XXX(0x2f, 0x2e2e); \
223	    XXX(0x34, 0x2e2e); \
224	    XXX(0x38, 0x2e2e); \
225	    XXX(0x3e, 0x2e2e); \
226	    UNI(0x47, 0x2426); \
227	    MAP(0x48, 0xc7); \
228	    MAP(0x49, 0xc8); \
229	    MAP(0x4a, 0xc9); \
230	    MAP(0x4b, 0xca); \
231	    MAP(0x4c, 0xcb); \
232	    MAP(0x4d, 0xcc); \
233	    MAP(0x4e, 0xcd); \
234	    MAP(0x4f, 0xce); \
235	    XXX(0x50, 0x2e2e); \
236	    UNI(0x57, 0x0152); \
237	    XXX(0x5e, 0x2e2e); \
238	    XXX(0x70, 0x2e2e); \
239	    UNI(0x77, 0x0153); \
240	    MAP(0x7d, 0xff); \
241	    XXX(0x7e, 0x2e2e); \
242	    default: dft; break; \
243	}
244
245#define map_SCS_DEC_Supp_Graphic(code,dft) \
246	switch (code) { \
247	    XXX(0x24, 0x2e2e); \
248	    XXX(0x26, 0x2e2e); \
249	    XXX(0x2c, 0x2e2e); \
250	    XXX(0x2d, 0x2e2e); \
251	    XXX(0x2e, 0x2e2e); \
252	    XXX(0x2f, 0x2e2e); \
253	    XXX(0x34, 0x2e2e); \
254	    XXX(0x38, 0x2e2e); \
255	    XXX(0x3e, 0x2e2e); \
256	    XXX(0x50, 0x2e2e); \
257	    UNI(0x57, 0x0152); \
258	    XXX(0x5e, 0x2e2e); \
259	    XXX(0x70, 0x2e2e); \
260	    UNI(0x77, 0x0153); \
261	    MAP(0x7d, 0xff); \
262	    XXX(0x7e, 0x2e2e); \
263	    XXX(0x7f, 0x2e2e); \
264	    default: dft; break; \
265	}
266
267	/* derived from http://www.vt100.net/charsets/technical.html */
268#if OPT_WIDE_CHARS
269#define map_SCS_DEC_Technical(code) \
270	switch (code) { \
271	    UNI(0x21, 0x23b7);	/* RADICAL SYMBOL BOTTOM Centred left to right, so that it joins up with 02/02 */ \
272	    UNI(0x22, 0x250c);	/* BOX DRAWINGS LIGHT DOWN AND RIGHT */ \
273	    UNI(0x23, 0x2500);	/* BOX DRAWINGS LIGHT HORIZONTAL */ \
274	    UNI(0x24, 0x2320);	/* TOP HALF INTEGRAL with the proviso that the stem is vertical, to join with 02/06 */ \
275	    UNI(0x25, 0x2321);	/* BOTTOM HALF INTEGRAL with the proviso above. */ \
276	    UNI(0x26, 0x2502);	/* BOX DRAWINGS LIGHT VERTICAL */ \
277	    UNI(0x27, 0x23a1);	/* LEFT SQUARE BRACKET UPPER CORNER Joins vertically to 02/06, 02/08. Doesn't join to its right. */ \
278	    UNI(0x28, 0x23a3);	/* LEFT SQUARE BRACKET LOWER CORNER Joins vertically to 02/06, 02/07. Doesn't join to its right. */ \
279	    UNI(0x29, 0x23a4);	/* RIGHT SQUARE BRACKET UPPER CORNER Joins vertically to 026, 02a. Doesn't join to its left. */ \
280	    UNI(0x2a, 0x23a6);	/* RIGHT SQUARE BRACKET LOWER CORNER Joins vertically to 026, 029. Doesn't join to its left. */ \
281	    UNI(0x2b, 0x239b);	/* LEFT PARENTHESIS UPPER HOOK Joins vertically to 026, 02c, 02/15. Doesn't join to its right. */ \
282	    UNI(0x2c, 0x239d);	/* LEFT PARENTHESIS LOWER HOOK Joins vertically to 026, 02b, 02/15. Doesn't join to its right. */ \
283	    UNI(0x2d, 0x239e);	/* RIGHT PARENTHESIS UPPER HOOK Joins vertically to 026, 02e, 03/00. Doesn't join to its left. */ \
284	    UNI(0x2e, 0x23a0);	/* RIGHT PARENTHESIS LOWER HOOK Joins vertically to 026, 02d, 03/00. Doesn't join to its left. */ \
285	    UNI(0x2f, 0x23a8);	/* LEFT CURLY BRACKET MIDDLE PIECE Joins vertically to 026, 02b, 02c. */ \
286	    UNI(0x30, 0x23ac);	/* RIGHT CURLY BRACKET MIDDLE PIECE Joins vertically to 02/06, 02d, 02e. */ \
287	    XXX(0x31, 0x2426);	/* Top Left Sigma. Joins to right with 02/03, 03/05. Joins diagonally below right with 03/03, 03/07. */ \
288	    XXX(0x32, 0x2426);	/* Bottom Left Sigma. Joins to right with 02/03, 03/06. Joins diagonally above right with 03/04, 03/07. */ \
289	    XXX(0x33, 0x2426);	/* Top Diagonal Sigma. Line for joining 03/01 to 03/04 or 03/07. */ \
290	    XXX(0x34, 0x2426);	/* Bottom Diagonal Sigma. Line for joining 03/02 to 03/03 or 03/07. */ \
291	    XXX(0x35, 0x2426);	/* Top Right Sigma. Joins to left with 02/03, 03/01. */ \
292	    XXX(0x36, 0x2426);	/* Bottom Right Sigma. Joins to left with 02/03, 03/02. */ \
293	    XXX(0x37, 0x2426);	/* Middle Sigma. Joins diagonally with 03/01, 03/02, 03/03, 03/04. */ \
294	    XXX(0x38, 0x2426);	/* undefined */ \
295	    XXX(0x39, 0x2426);	/* undefined */ \
296	    XXX(0x3a, 0x2426);	/* undefined */ \
297	    XXX(0x3b, 0x2426);	/* undefined */ \
298	    UNI(0x3c, 0x2264);	/* LESS-THAN OR EQUAL TO */ \
299	    UNI(0x3d, 0x2260);	/* NOT EQUAL TO */ \
300	    UNI(0x3e, 0x2265);	/* GREATER-THAN OR EQUAL TO */ \
301	    UNI(0x3f, 0x222B);	/* INTEGRAL */ \
302	    UNI(0x40, 0x2234);	/* THEREFORE */ \
303	    UNI(0x41, 0x221d);	/* PROPORTIONAL TO */ \
304	    UNI(0x42, 0x221e);	/* INFINITY */ \
305	    UNI(0x43, 0x00f7);	/* DIVISION SIGN */ \
306	    UNI(0x44, 0x039a);	/* GREEK CAPITAL DELTA */ \
307	    UNI(0x45, 0x2207);	/* NABLA */ \
308	    UNI(0x46, 0x03a6);	/* GREEK CAPITAL LETTER PHI */ \
309	    UNI(0x47, 0x0393);	/* GREEK CAPITAL LETTER GAMMA */ \
310	    UNI(0x48, 0x223c);	/* TILDE OPERATOR */ \
311	    UNI(0x49, 0x2243);	/* ASYMPTOTICALLY EQUAL TO */ \
312	    UNI(0x4a, 0x0398);	/* GREEK CAPITAL LETTER THETA */ \
313	    UNI(0x4b, 0x00d7);	/* MULTIPLICATION SIGN */ \
314	    UNI(0x4c, 0x039b);	/* GREEK CAPITAL LETTER LAMDA */ \
315	    UNI(0x4d, 0x21d4);	/* LEFT RIGHT DOUBLE ARROW */ \
316	    UNI(0x4e, 0x21d2);	/* RIGHTWARDS DOUBLE ARROW */ \
317	    UNI(0x4f, 0x2261);	/* IDENTICAL TO */ \
318	    UNI(0x50, 0x03a0);	/* GREEK CAPITAL LETTER PI */ \
319	    UNI(0x51, 0x03a8);	/* GREEK CAPITAL LETTER PSI */ \
320	    UNI(0x52, 0x2426);	/* undefined */ \
321	    UNI(0x53, 0x03a3);	/* GREEK CAPITAL LETTER SIGMA */ \
322	    XXX(0x54, 0x2426);	/* undefined */ \
323	    XXX(0x55, 0x2426);	/* undefined */ \
324	    UNI(0x56, 0x221a);	/* SQUARE ROOT */ \
325	    UNI(0x57, 0x03a9);	/* GREEK CAPITAL LETTER OMEGA */ \
326	    UNI(0x58, 0x039e);	/* GREEK CAPITAL LETTER XI */ \
327	    UNI(0x59, 0x03a5);	/* GREEK CAPITAL LETTER UPSILON */ \
328	    UNI(0x5a, 0x2282);	/* SUBSET OF */ \
329	    UNI(0x5b, 0x2283);	/* SUPERSET OF */ \
330	    UNI(0x5c, 0x2229);	/* INTERSECTION */ \
331	    UNI(0x5d, 0x222a);	/* UNION */ \
332	    UNI(0x5e, 0x2227);	/* LOGICAL AND */ \
333	    UNI(0x5f, 0x2228);	/* LOGICAL OR */ \
334	    UNI(0x60, 0x00ac);	/* NOT SIGN */ \
335	    UNI(0x61, 0x03b1);	/* GREEK SMALL LETTER ALPHA */ \
336	    UNI(0x62, 0x03b2);	/* GREEK SMALL LETTER BETA */ \
337	    UNI(0x63, 0x03c7);	/* GREEK SMALL LETTER CHI */ \
338	    UNI(0x64, 0x03b4);	/* GREEK SMALL LETTER DELTA */ \
339	    UNI(0x65, 0x03b5);	/* GREEK SMALL LETTER EPSILON */ \
340	    UNI(0x66, 0x03c6);	/* GREEK SMALL LETTER PHI */ \
341	    UNI(0x67, 0x03b3);	/* GREEK SMALL LETTER GAMMA */ \
342	    UNI(0x68, 0x03b7);	/* GREEK SMALL LETTER ETA */ \
343	    UNI(0x69, 0x03b9);	/* GREEK SMALL LETTER IOTA */ \
344	    UNI(0x6a, 0x03b8);	/* GREEK SMALL LETTER THETA */ \
345	    UNI(0x6b, 0x03ba);	/* GREEK SMALL LETTER KAPPA */ \
346	    UNI(0x6c, 0x03bb);	/* GREEK SMALL LETTER LAMDA */ \
347	    XXX(0x6d, 0x2426);	/* undefined */ \
348	    UNI(0x6e, 0x03bd);	/* GREEK SMALL LETTER NU */ \
349	    UNI(0x6f, 0x2202);	/* PARTIAL DIFFERENTIAL */ \
350	    UNI(0x70, 0x03c0);	/* GREEK SMALL LETTER PI */ \
351	    UNI(0x71, 0x03c8);	/* GREEK SMALL LETTER PSI */ \
352	    UNI(0x72, 0x03c1);	/* GREEK SMALL LETTER RHO */ \
353	    UNI(0x73, 0x03c3);	/* GREEK SMALL LETTER SIGMA */ \
354	    UNI(0x74, 0x03c4);	/* GREEK SMALL LETTER TAU */ \
355	    XXX(0x75, 0x2426);	/* undefined */ \
356	    UNI(0x76, 0x0192);	/* LATIN SMALL LETTER F WITH HOOK Probably chosen for its meaning of "function" */ \
357	    UNI(0x77, 0x03c9);	/* GREEK SMALL LETTER OMEGA */ \
358	    UNI(0x78, 0x03bE);	/* GREEK SMALL LETTER XI */ \
359	    UNI(0x79, 0x03c5);	/* GREEK SMALL LETTER UPSILON */ \
360	    UNI(0x7a, 0x03b6);	/* GREEK SMALL LETTER ZETA */ \
361	    UNI(0x7b, 0x2190);	/* LEFTWARDS ARROW */ \
362	    UNI(0x7c, 0x2191);	/* UPWARDS ARROW */ \
363	    UNI(0x7d, 0x2192);	/* RIGHTWARDS ARROW */ \
364	    UNI(0x7e, 0x2193);	/* DOWNWARDS ARROW */ \
365	}
366#else
367#define map_SCS_DEC_Technical(code)	/* nothing */
368#endif /* OPT_WIDE_CHARS */
369
370/*
371 * Translate an input keysym to the corresponding NRC keysym.
372 */
373unsigned
374xtermCharSetIn(TScreen *screen, unsigned code, int charset)
375{
376#define MAP(to, from) case from: code = to; break
377
378#if OPT_WIDE_CHARS
379#define UNI(to, from) case from: if (screen->utf8_nrc_mode) code = to; break
380#else
381#define UNI(to, from) case from: break
382#endif
383
384#define XXX(to, from)		/* no defined mapping to 0..255 */
385
386    TRACE(("CHARSET-IN GL=%s(G%d) GR=%s(G%d) SS%d\n\t%s\n",
387	   visibleScsCode(screen->gsets[screen->curgl]), screen->curgl,
388	   visibleScsCode(screen->gsets[screen->curgr]), screen->curgr,
389	   screen->curss,
390	   visibleUChar(code)));
391
392    switch (charset) {
393    case nrc_British:		/* United Kingdom set (or Latin 1)      */
394	if (code == XK_sterling)
395	    code = 0x23;
396	code &= 0x7f;
397	break;
398
399#if OPT_XMC_GLITCH
400    case nrc_Unknown:
401#endif
402    case nrc_DEC_Alt_Chars:
403    case nrc_DEC_Alt_Graphics:
404    case nrc_ASCII:
405	break;
406
407    case nrc_DEC_Spec_Graphic:
408	break;
409
410    case nrc_DEC_Supp:
411	map_SCS_DEC_Supp(code, code &= 0x7f);
412	break;
413
414    case nrc_DEC_Supp_Graphic:
415	map_SCS_DEC_Supp_Graphic(code, code |= 0x80);
416	break;
417
418    case nrc_DEC_Technical:
419	map_SCS_DEC_Technical(code);
420	break;
421
422    case nrc_Dutch:
423	map_NRCS_Dutch(code);
424	break;
425
426    case nrc_Finnish:
427    case nrc_Finnish2:
428	map_NRCS_Finnish(code);
429	break;
430
431    case nrc_French:
432    case nrc_French2:
433	map_NRCS_French(code);
434	break;
435
436    case nrc_French_Canadian:
437	map_NRCS_French_Canadian(code);
438	break;
439
440    case nrc_German:
441	map_NRCS_German(code);
442	break;
443
444    case nrc_Hebrew:
445    case nrc_Hebrew2:
446	/* FIXME */
447	break;
448
449    case nrc_Italian:
450	map_NRCS_Italian(code);
451	break;
452
453    case nrc_Norwegian_Danish:
454    case nrc_Norwegian_Danish2:
455    case nrc_Norwegian_Danish3:
456	map_NRCS_Norwegian_Danish(code);
457	break;
458
459    case nrc_Portugese:
460	map_NRCS_Portuguese(code);
461	break;
462
463    case nrc_SCS_NRCS:		/* vt5xx - probably Serbo/Croatian */
464	/* FIXME */
465	break;
466
467    case nrc_Spanish:
468	map_NRCS_Spanish(code);
469	break;
470
471    case nrc_Swedish2:
472    case nrc_Swedish:
473	map_NRCS_Swedish(code);
474	break;
475
476    case nrc_Swiss:
477	map_NRCS_Swiss(code);
478	break;
479
480    case nrc_Turkish:
481    case nrc_Turkish2:
482	/* FIXME */
483	break;
484
485    default:			/* any character sets we don't recognize */
486	break;
487    }
488    code &= 0x7f;		/* NRC in any case is 7-bit */
489    TRACE(("->\t%s\n",
490	   visibleUChar(code)));
491    return code;
492#undef MAP
493#undef UNI
494#undef XXX
495}
496
497/*
498 * Translate a string to the display form.  This assumes the font has the
499 * DEC graphic characters in cells 0-31, and otherwise is ISO-8859-1.
500 */
501int
502xtermCharSetOut(XtermWidget xw, IChar *buf, IChar *ptr, int leftset)
503{
504    IChar *s;
505    TScreen *screen = TScreenOf(xw);
506    int count = 0;
507    int rightset = screen->gsets[(int) (screen->curgr)];
508
509#define MAP(from, to) case from: chr = to; break
510
511#if OPT_WIDE_CHARS
512#define UNI(from, to) case from: if (screen->utf8_nrc_mode) chr = to; break
513#define XXX(from, to) UNI(from, to)
514#else
515#define UNI(old, new) chr = old; break
516#define XXX(from, to)		/* nothing */
517#endif
518
519    TRACE(("CHARSET-OUT GL=%s(G%d) GR=%s(G%d) SS%d\n\t%s\n",
520	   visibleScsCode(leftset), screen->curgl,
521	   visibleScsCode(rightset), screen->curgr,
522	   screen->curss,
523	   visibleIChars(buf, (unsigned) (ptr - buf))));
524
525    for (s = buf; s < ptr; ++s) {
526	int eight = CharOf(E2A(*s));
527	int seven = eight & 0x7f;
528	int cs = (eight >= 128) ? rightset : leftset;
529	int chr = eight;
530
531	count++;
532#if OPT_WIDE_CHARS
533	/*
534	 * This is only partly right - prevent inadvertant remapping of
535	 * the replacement character and other non-8bit codes into bogus
536	 * 8bit codes.
537	 */
538	if (screen->utf8_mode || screen->utf8_nrc_mode) {
539	    if (*s > 255)
540		continue;
541	}
542#endif
543	if (*s < 32)
544	    continue;
545
546	switch (cs) {
547	case nrc_British_Latin_1:
548	    /* FALLTHRU */
549	case nrc_British:	/* United Kingdom set (or Latin 1)      */
550	    if ((xw->flags & NATIONAL)
551		|| (screen->vtXX_level <= 1)) {
552		if ((xw->flags & NATIONAL)) {
553		    chr = seven;
554		}
555		if (chr == 0x23) {
556		    chr = XTERM_POUND;
557#if OPT_WIDE_CHARS
558		    if (screen->utf8_nrc_mode) {
559			chr = 0xa3;
560		    }
561#endif
562		}
563	    } else {
564		chr = (seven | 0x80);
565	    }
566	    break;
567
568#if OPT_XMC_GLITCH
569	case nrc_Unknown:
570#endif
571	case nrc_DEC_Alt_Chars:
572	case nrc_DEC_Alt_Graphics:
573	case nrc_ASCII:
574	    break;
575
576	case nrc_DEC_Spec_Graphic:
577	    if (seven > 0x5f && seven <= 0x7e) {
578#if OPT_WIDE_CHARS
579		if (screen->utf8_mode || screen->utf8_nrc_mode)
580		    chr = (int) dec2ucs((unsigned) (seven - 0x5f));
581		else
582#endif
583		    chr = seven - 0x5f;
584	    } else {
585		chr = seven;
586	    }
587	    break;
588
589	case nrc_DEC_Supp:
590	    map_SCS_DEC_Supp(chr = seven, chr |= 0x80);
591	    break;
592
593	case nrc_DEC_Supp_Graphic:
594	    map_SCS_DEC_Supp_Graphic(chr = seven, chr |= 0x80);
595	    break;
596
597	case nrc_DEC_Technical:
598	    map_SCS_DEC_Technical(chr = seven);
599	    break;
600
601	case nrc_Dutch:
602	    map_NRCS_Dutch(chr = seven);
603	    break;
604
605	case nrc_Finnish:
606	case nrc_Finnish2:
607	    map_NRCS_Finnish(chr = seven);
608	    break;
609
610	case nrc_French:
611	case nrc_French2:
612	    map_NRCS_French(chr = seven);
613	    break;
614
615	case nrc_French_Canadian:
616	case nrc_French_Canadian2:
617	    map_NRCS_French_Canadian(chr = seven);
618	    break;
619
620	case nrc_German:
621	    map_NRCS_German(chr = seven);
622	    break;
623
624	case nrc_Hebrew:
625	case nrc_Hebrew2:
626	    /* FIXME */
627	    break;
628
629	case nrc_Italian:
630	    map_NRCS_Italian(chr = seven);
631	    break;
632
633	case nrc_Norwegian_Danish:
634	case nrc_Norwegian_Danish2:
635	case nrc_Norwegian_Danish3:
636	    map_NRCS_Norwegian_Danish(chr = seven);
637	    break;
638
639	case nrc_Portugese:
640	    map_NRCS_Portuguese(chr = seven);
641	    break;
642
643	case nrc_SCS_NRCS:	/* vt5xx - probably Serbo/Croatian */
644	    /* FIXME */
645	    break;
646
647	case nrc_Spanish:
648	    map_NRCS_Spanish(chr = seven);
649	    break;
650
651	case nrc_Swedish2:
652	case nrc_Swedish:
653	    map_NRCS_Swedish(chr = seven);
654	    break;
655
656	case nrc_Swiss:
657	    map_NRCS_Swiss(chr = seven);
658	    break;
659
660	case nrc_Turkish:
661	case nrc_Turkish2:
662	    /* FIXME */
663	    break;
664
665	default:		/* any character sets we don't recognize */
666	    count--;
667	    break;
668	}
669	/*
670	 * The state machine already treated DEL as a nonprinting and
671	 * nonspacing character.  If we have DEL now, simply render
672	 * it as a blank.
673	 */
674	if (chr == ANSI_DEL)
675	    chr = ' ';
676	*s = (IChar) A2E(chr);
677    }
678    TRACE(("%d\t%s\n",
679	   count,
680	   visibleIChars(buf, (unsigned) (ptr - buf))));
681    return count;
682#undef MAP
683#undef UNI
684#undef XXX
685}
686