15104ee6eSmrg/* $XTermId: charsets.c,v 1.129 2024/10/03 22:21:32 tom Exp $ */
2d522f475Smrg
30bd37d32Smrg/*
404b94745Smrg * Copyright 1998-2023,2024 by Thomas E. Dickey
50bd37d32Smrg *
60bd37d32Smrg *                         All Rights Reserved
70bd37d32Smrg *
80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90bd37d32Smrg * copy of this software and associated documentation files (the
100bd37d32Smrg * "Software"), to deal in the Software without restriction, including
110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish,
120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to
130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to
140bd37d32Smrg * the following conditions:
150bd37d32Smrg *
160bd37d32Smrg * The above copyright notice and this permission notice shall be included
170bd37d32Smrg * in all copies or substantial portions of the Software.
180bd37d32Smrg *
190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
260bd37d32Smrg *
270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright
280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the
290bd37d32Smrg * sale, use or other dealings in this Software without prior written
300bd37d32Smrg * authorization.
310bd37d32Smrg *
320bd37d32Smrg */
33d522f475Smrg
3404b94745Smrg#include <assert.h>
3504b94745Smrg#include <X11/keysym.h>
3604b94745Smrg
37d522f475Smrg#include <xterm.h>
38d522f475Smrg#include <data.h>
3904b94745Smrg#include <charsets.h>
40d522f475Smrg#include <fontutils.h>
41d522f475Smrg
42d522f475Smrg/*
43d522f475Smrg * This module performs translation as needed to support the DEC VT220 national
44f2e35a3aSmrg * replacement character sets as well as supplementary character sets (aka
45f2e35a3aSmrg * code-pages) introduced in VT320, etc.
46f2e35a3aSmrg *
47f2e35a3aSmrg * We assume that xterm's font is based on the ISO 8859-1 (Latin 1) character
48f2e35a3aSmrg * set, which is almost the same as the DEC multinational character set.  Glyph
49f2e35a3aSmrg * positions 0-31 have to be the DEC graphic characters, though.
50d522f475Smrg *
51d522f475Smrg * References:
52d522f475Smrg *	"VT220 Programmer Pocket Guide" EK-VT220-HR-002 (2nd ed., 1984), which
53d522f475Smrg *		contains character charts for the national character sets.
54d522f475Smrg *	"VT330/VT340 Programmer Reference Manual Volume 1: Text Programming"
55d522f475Smrg *		EK-VT3XX-TP-001 (1st ed, 1987), which contains a table (2-1)
56d522f475Smrg *		listing the glyphs which are mapped from the multinational
57d522f475Smrg *		character set to the national character set.
58d522f475Smrg *
59d522f475Smrg * The latter reference, though easier to read, has a few errors and omissions.
60f2e35a3aSmrg */
612eaa94a1Schristos
6204b94745Smrg#define HandleUPSS(charset) \
6304b94745Smrg    if (charset == nrc_DEC_UPSS) { \
6404b94745Smrg	charset = screen->gsets_upss; \
6504b94745Smrg	if (screen->vtXX_level >= 5) { \
6604b94745Smrg	    /* EMPTY */ ; \
6704b94745Smrg	} else if (screen->vtXX_level >= 3) { \
6804b94745Smrg	    if (charset != nrc_DEC_Supp) \
6904b94745Smrg		charset = nrc_ISO_Latin_1_Supp; \
7004b94745Smrg	} else if (screen->vtXX_level < 2) { \
7104b94745Smrg	    charset = nrc_ASCII; \
72f2e35a3aSmrg	} \
7304b94745Smrg    }
742eaa94a1Schristos
7504b94745Smrgstatic Boolean
7604b94745SmrgisSevenBit(DECNRCM_codes cs)
7704b94745Smrg{
7804b94745Smrg    Boolean result = False;
7904b94745Smrg
8004b94745Smrg    switch (cs) {
8104b94745Smrg    case nrc_ISO_Greek_Supp:
8204b94745Smrg    case nrc_ISO_Hebrew_Supp:
8304b94745Smrg    case nrc_ISO_Latin_1_Supp:
8404b94745Smrg    case nrc_ISO_Latin_2_Supp:
8504b94745Smrg    case nrc_ISO_Latin_5_Supp:
8604b94745Smrg    case nrc_ISO_Latin_Cyrillic:
8704b94745Smrg    case nrc_DEC_UPSS:
8804b94745Smrg	break;
8904b94745Smrg	/* VT100 character sets */
9004b94745Smrg    case nrc_ASCII:
9104b94745Smrg    case nrc_British:
9204b94745Smrg    case nrc_DEC_Alt_Chars:
9304b94745Smrg    case nrc_DEC_Spec_Graphic:
9404b94745Smrg	/* VT220 character sets */
9504b94745Smrg    case nrc_DEC_Alt_Graphics:
9604b94745Smrg    case nrc_DEC_Supp:
9704b94745Smrg	/* VT320 character sets */
9804b94745Smrg    case nrc_DEC_Supp_Graphic:
9904b94745Smrg    case nrc_DEC_Technical:
10004b94745Smrg	/* NRCS character sets (VT320 to VT520) */
10104b94745Smrg    case nrc_British_Latin_1:
10204b94745Smrg    case nrc_Dutch:
10304b94745Smrg    case nrc_Finnish2:
10404b94745Smrg    case nrc_Finnish:
10504b94745Smrg    case nrc_French2:
10604b94745Smrg    case nrc_French:
10704b94745Smrg    case nrc_French_Canadian2:
10804b94745Smrg    case nrc_French_Canadian:
10904b94745Smrg    case nrc_German:
11004b94745Smrg    case nrc_Greek:
11104b94745Smrg    case nrc_Hebrew:
11204b94745Smrg    case nrc_Italian:
1135104ee6eSmrg    case nrc_JIS_Katakana:
1145104ee6eSmrg    case nrc_JIS_Roman:
11504b94745Smrg    case nrc_Norwegian_Danish2:
11604b94745Smrg    case nrc_Norwegian_Danish3:
11704b94745Smrg    case nrc_Norwegian_Danish:
11804b94745Smrg    case nrc_Portugese:
11904b94745Smrg    case nrc_Russian:
12004b94745Smrg    case nrc_SCS_NRCS:
12104b94745Smrg    case nrc_Spanish:
12204b94745Smrg    case nrc_Swedish2:
12304b94745Smrg    case nrc_Swedish:
12404b94745Smrg    case nrc_Swiss:
12504b94745Smrg    case nrc_Turkish:
12604b94745Smrg	/* other DEC character sets */
12704b94745Smrg    case nrc_DEC_Cyrillic:
12804b94745Smrg    case nrc_DEC_Greek_Supp:
12904b94745Smrg    case nrc_DEC_Hebrew_Supp:
13004b94745Smrg    case nrc_DEC_Turkish_Supp:
13104b94745Smrg	result = True;
13204b94745Smrg	break;
13304b94745Smrg    case nrc_Unknown:
13404b94745Smrg	break;
13504b94745Smrg    }
13604b94745Smrg    return result;
13704b94745Smrg}
138e0a2b6dfSmrg
139e0a2b6dfSmrg/*
140e0a2b6dfSmrg * Translate an input keysym to the corresponding NRC keysym.
141e0a2b6dfSmrg */
142e0a2b6dfSmrgunsigned
143f2e35a3aSmrgxtermCharSetIn(XtermWidget xw, unsigned code, DECNRCM_codes charset)
144e0a2b6dfSmrg{
145f2e35a3aSmrg    TScreen *screen = TScreenOf(xw);
14604b94745Smrg#define MAP(to, from) case from: code = to; break;
147e0a2b6dfSmrg
148e0a2b6dfSmrg#if OPT_WIDE_CHARS
14904b94745Smrg#define UNI(to, from) case from: if (screen->utf8_nrc_mode) code = to; break;
150e0a2b6dfSmrg#else
15104b94745Smrg#define UNI(to, from) case from: break;
152e0a2b6dfSmrg#endif
153e0a2b6dfSmrg
154e0a2b6dfSmrg#define XXX(to, from)		/* no defined mapping to 0..255 */
155e0a2b6dfSmrg
156e0a2b6dfSmrg    TRACE(("CHARSET-IN GL=%s(G%d) GR=%s(G%d) SS%d\n\t%s\n",
157e0a2b6dfSmrg	   visibleScsCode(screen->gsets[screen->curgl]), screen->curgl,
158e0a2b6dfSmrg	   visibleScsCode(screen->gsets[screen->curgr]), screen->curgr,
159e0a2b6dfSmrg	   screen->curss,
160e0a2b6dfSmrg	   visibleUChar(code)));
161e0a2b6dfSmrg
16204b94745Smrg    HandleUPSS(charset);
16304b94745Smrg
164e0a2b6dfSmrg    switch (charset) {
165e0a2b6dfSmrg    case nrc_British:		/* United Kingdom set (or Latin 1)      */
166e0a2b6dfSmrg	if (code == XK_sterling)
167e0a2b6dfSmrg	    code = 0x23;
168e0a2b6dfSmrg	code &= 0x7f;
169e0a2b6dfSmrg	break;
170e0a2b6dfSmrg
171e0a2b6dfSmrg    case nrc_DEC_Alt_Chars:
172e0a2b6dfSmrg    case nrc_DEC_Alt_Graphics:
173e0a2b6dfSmrg    case nrc_ASCII:
174e0a2b6dfSmrg	break;
175e0a2b6dfSmrg
176e0a2b6dfSmrg    case nrc_DEC_Spec_Graphic:
177e0a2b6dfSmrg	break;
178e0a2b6dfSmrg
179e0a2b6dfSmrg    case nrc_DEC_Supp:
180f2e35a3aSmrg	map_DEC_Supp_Graphic(code, code &= 0x7f);
181e0a2b6dfSmrg	break;
182e0a2b6dfSmrg
183e0a2b6dfSmrg    case nrc_DEC_Supp_Graphic:
184f2e35a3aSmrg	map_DEC_Supp_Graphic(code, code |= 0x80);
185e0a2b6dfSmrg	break;
186e0a2b6dfSmrg
187e0a2b6dfSmrg    case nrc_DEC_Technical:
188f2e35a3aSmrg	map_DEC_Technical(code);
189e0a2b6dfSmrg	break;
190e0a2b6dfSmrg
191e0a2b6dfSmrg    case nrc_Dutch:
192e0a2b6dfSmrg	map_NRCS_Dutch(code);
193e0a2b6dfSmrg	break;
194e0a2b6dfSmrg
195e0a2b6dfSmrg    case nrc_Finnish:
196e0a2b6dfSmrg    case nrc_Finnish2:
197e0a2b6dfSmrg	map_NRCS_Finnish(code);
198e0a2b6dfSmrg	break;
199e0a2b6dfSmrg
200e0a2b6dfSmrg    case nrc_French:
201e0a2b6dfSmrg    case nrc_French2:
202e0a2b6dfSmrg	map_NRCS_French(code);
203e0a2b6dfSmrg	break;
204e0a2b6dfSmrg
205e0a2b6dfSmrg    case nrc_French_Canadian:
206e0a2b6dfSmrg	map_NRCS_French_Canadian(code);
207e0a2b6dfSmrg	break;
208e0a2b6dfSmrg
209e0a2b6dfSmrg    case nrc_German:
210e0a2b6dfSmrg	map_NRCS_German(code);
211e0a2b6dfSmrg	break;
212e0a2b6dfSmrg
213f2e35a3aSmrg    case nrc_Greek:
214f2e35a3aSmrg	map_NRCS_Greek(code);	/* FIXME - ELOT? */
215f2e35a3aSmrg	break;
216f2e35a3aSmrg
217f2e35a3aSmrg    case nrc_DEC_Greek_Supp:
218f2e35a3aSmrg	map_DEC_Greek_Supp(code);
219f2e35a3aSmrg	break;
220f2e35a3aSmrg
221f2e35a3aSmrg    case nrc_ISO_Greek_Supp:
222f2e35a3aSmrg	map_ISO_Greek_Supp(code);
223f2e35a3aSmrg	break;
224f2e35a3aSmrg
225f2e35a3aSmrg    case nrc_DEC_Hebrew_Supp:
226f2e35a3aSmrg	map_DEC_Hebrew_Supp(code);
227f2e35a3aSmrg	break;
228f2e35a3aSmrg
229e0a2b6dfSmrg    case nrc_Hebrew:
230f2e35a3aSmrg	map_NRCS_Hebrew(code);
231f2e35a3aSmrg	break;
232f2e35a3aSmrg
233f2e35a3aSmrg    case nrc_ISO_Hebrew_Supp:
234f2e35a3aSmrg	map_ISO_Hebrew(code);
235e0a2b6dfSmrg	break;
236e0a2b6dfSmrg
237e0a2b6dfSmrg    case nrc_Italian:
238e0a2b6dfSmrg	map_NRCS_Italian(code);
239e0a2b6dfSmrg	break;
240e0a2b6dfSmrg
241f2e35a3aSmrg    case nrc_ISO_Latin_2_Supp:
242f2e35a3aSmrg	map_ISO_Latin_2(code);
243f2e35a3aSmrg	break;
244f2e35a3aSmrg
245f2e35a3aSmrg    case nrc_ISO_Latin_5_Supp:
246f2e35a3aSmrg	map_ISO_Latin_5(code);
247f2e35a3aSmrg	break;
248f2e35a3aSmrg
249f2e35a3aSmrg    case nrc_ISO_Latin_Cyrillic:
250f2e35a3aSmrg	map_ISO_Latin_Cyrillic(code);
251f2e35a3aSmrg	break;
252f2e35a3aSmrg
2535104ee6eSmrg    case nrc_JIS_Katakana:
2545104ee6eSmrg	map_JIS_Katakana(code);
2555104ee6eSmrg	break;
2565104ee6eSmrg
2575104ee6eSmrg    case nrc_JIS_Roman:
2585104ee6eSmrg	map_JIS_Roman(code);
2595104ee6eSmrg	break;
2605104ee6eSmrg
261e0a2b6dfSmrg    case nrc_Norwegian_Danish:
262e0a2b6dfSmrg    case nrc_Norwegian_Danish2:
263e0a2b6dfSmrg    case nrc_Norwegian_Danish3:
264e0a2b6dfSmrg	map_NRCS_Norwegian_Danish(code);
265e0a2b6dfSmrg	break;
266e0a2b6dfSmrg
267e0a2b6dfSmrg    case nrc_Portugese:
268e0a2b6dfSmrg	map_NRCS_Portuguese(code);
269e0a2b6dfSmrg	break;
270e0a2b6dfSmrg
2715104ee6eSmrg    case nrc_Russian:
2725104ee6eSmrg	map_NRCS_Russian(code);
2735104ee6eSmrg	break;
2745104ee6eSmrg
27504b94745Smrg    case nrc_SCS_NRCS:		/* vt5xx - Serbo/Croatian */
2765104ee6eSmrg	map_NRCS_Serbo_Croatian(code);
277e0a2b6dfSmrg	break;
278e0a2b6dfSmrg
279e0a2b6dfSmrg    case nrc_Spanish:
280e0a2b6dfSmrg	map_NRCS_Spanish(code);
281e0a2b6dfSmrg	break;
282e0a2b6dfSmrg
283e0a2b6dfSmrg    case nrc_Swedish2:
284e0a2b6dfSmrg    case nrc_Swedish:
285e0a2b6dfSmrg	map_NRCS_Swedish(code);
286e0a2b6dfSmrg	break;
287e0a2b6dfSmrg
288e0a2b6dfSmrg    case nrc_Swiss:
289e0a2b6dfSmrg	map_NRCS_Swiss(code);
290e0a2b6dfSmrg	break;
291e0a2b6dfSmrg
292e0a2b6dfSmrg    case nrc_Turkish:
293f2e35a3aSmrg	map_NRCS_Turkish(code);
294f2e35a3aSmrg	break;
295f2e35a3aSmrg
296f2e35a3aSmrg    case nrc_DEC_Turkish_Supp:
297f2e35a3aSmrg	map_DEC_Turkish_Supp(code);
298e0a2b6dfSmrg	break;
299e0a2b6dfSmrg
300f2e35a3aSmrg    case nrc_DEC_Cyrillic:
301f2e35a3aSmrg	map_DEC_Cyrillic(code);
302f2e35a3aSmrg	break;
303f2e35a3aSmrg
304f2e35a3aSmrg    case nrc_ISO_Latin_1_Supp:
305f2e35a3aSmrg    case nrc_British_Latin_1:
306f2e35a3aSmrg    case nrc_French_Canadian2:
307f2e35a3aSmrg    case nrc_Unknown:
30804b94745Smrg    case nrc_DEC_UPSS:
309e0a2b6dfSmrg    default:			/* any character sets we don't recognize */
310e0a2b6dfSmrg	break;
3112eaa94a1Schristos    }
312e0a2b6dfSmrg    code &= 0x7f;		/* NRC in any case is 7-bit */
313e0a2b6dfSmrg    TRACE(("->\t%s\n",
314e0a2b6dfSmrg	   visibleUChar(code)));
3152eaa94a1Schristos    return code;
3162eaa94a1Schristos#undef MAP
317e0a2b6dfSmrg#undef UNI
318e0a2b6dfSmrg#undef XXX
319d522f475Smrg}
320d522f475Smrg
321d522f475Smrg/*
322d522f475Smrg * Translate a string to the display form.  This assumes the font has the
323d522f475Smrg * DEC graphic characters in cells 0-31, and otherwise is ISO-8859-1.
324d522f475Smrg */
32504b94745SmrgCardinal
32604b94745SmrgxtermCharSetOut(XtermWidget xw, Cardinal length, DECNRCM_codes leftset)
327d522f475Smrg{
32804b94745Smrg    IChar *buf = xw->work.write_text;
32904b94745Smrg    IChar *ptr = buf + length;
3302eaa94a1Schristos    IChar *s;
3312eaa94a1Schristos    TScreen *screen = TScreenOf(xw);
33204b94745Smrg    Cardinal count = 0;
333f2e35a3aSmrg    DECNRCM_codes rightset = screen->gsets[(int) (screen->curgr)];
33404b94745Smrg#if OPT_DEC_RECTOPS
33504b94745Smrg    int sums = 0;
33604b94745Smrg#endif
3372eaa94a1Schristos
33804b94745Smrg#define MAP(from, to) case from: chr = to; break;
3392eaa94a1Schristos
340e0a2b6dfSmrg#if OPT_WIDE_CHARS
34104b94745Smrg#define UNI(from, to) case from: if (screen->utf8_nrc_mode) chr = to; break;
342e0a2b6dfSmrg#define XXX(from, to) UNI(from, to)
343e0a2b6dfSmrg#else
34404b94745Smrg#define UNI(old, new) case new: chr = old; break;
345e0a2b6dfSmrg#define XXX(from, to)		/* nothing */
346e0a2b6dfSmrg#endif
347e0a2b6dfSmrg
348e0a2b6dfSmrg    TRACE(("CHARSET-OUT GL=%s(G%d) GR=%s(G%d) SS%d\n\t%s\n",
349e0a2b6dfSmrg	   visibleScsCode(leftset), screen->curgl,
350e0a2b6dfSmrg	   visibleScsCode(rightset), screen->curgr,
3512eaa94a1Schristos	   screen->curss,
35204b94745Smrg	   visibleIChars(buf, (size_t) length)));
35304b94745Smrg
35404b94745Smrg    assert(length != 0);
35504b94745Smrg#if OPT_DEC_RECTOPS
35604b94745Smrg    if (length != 0 && length > xw->work.sizeof_sums) {
35704b94745Smrg	xw->work.sizeof_sums += length + 80;
35804b94745Smrg	xw->work.buffer_sums = realloc(xw->work.buffer_sums,
35904b94745Smrg				       xw->work.sizeof_sums);
36004b94745Smrg	xw->work.buffer_sets = realloc(xw->work.buffer_sets,
36104b94745Smrg				       xw->work.sizeof_sums);
36204b94745Smrg    }
36304b94745Smrg    xw->work.write_sums = xw->work.buffer_sums;
36404b94745Smrg#endif
3652eaa94a1Schristos
3662eaa94a1Schristos    for (s = buf; s < ptr; ++s) {
3675104ee6eSmrg	int eight = CharOf(*s);
3682eaa94a1Schristos	int seven = eight & 0x7f;
369f2e35a3aSmrg	DECNRCM_codes cs = (eight >= 128) ? rightset : leftset;
3702eaa94a1Schristos	int chr = eight;
3712eaa94a1Schristos
37204b94745Smrg	HandleUPSS(cs);
37304b94745Smrg
37404b94745Smrg#if OPT_DEC_RECTOPS
37504b94745Smrg	if (xw->work.buffer_sums != NULL && xw->work.buffer_sets != NULL) {
37604b94745Smrg	    xw->work.buffer_sums[sums] = (Char) ((eight < 32 || eight > 255)
37704b94745Smrg						 ? ANSI_ESC
37804b94745Smrg						 : eight);
37904b94745Smrg	    xw->work.buffer_sets[sums] = cs;
38004b94745Smrg	    ++sums;
38104b94745Smrg	}
38204b94745Smrg#endif
3832eaa94a1Schristos	count++;
3842eaa94a1Schristos#if OPT_WIDE_CHARS
3852eaa94a1Schristos	/*
386f2e35a3aSmrg	 * This is only partly right - prevent inadvertent remapping of
3872eaa94a1Schristos	 * the replacement character and other non-8bit codes into bogus
3882eaa94a1Schristos	 * 8bit codes.
3892eaa94a1Schristos	 */
390e0a2b6dfSmrg	if (screen->utf8_mode || screen->utf8_nrc_mode) {
3912eaa94a1Schristos	    if (*s > 255)
3922eaa94a1Schristos		continue;
3932eaa94a1Schristos	}
3942eaa94a1Schristos#endif
395e0a2b6dfSmrg	if (*s < 32)
396e0a2b6dfSmrg	    continue;
397e0a2b6dfSmrg
3982eaa94a1Schristos	switch (cs) {
39904b94745Smrg	case nrc_DEC_UPSS:
40004b94745Smrg	    break;
40104b94745Smrg
402f2e35a3aSmrg	case nrc_ISO_Latin_1_Supp:
403e0a2b6dfSmrg	case nrc_British_Latin_1:
404e0a2b6dfSmrg	case nrc_British:	/* United Kingdom set (or Latin 1)      */
4052eaa94a1Schristos	    if ((xw->flags & NATIONAL)
4062eaa94a1Schristos		|| (screen->vtXX_level <= 1)) {
407e0a2b6dfSmrg		if ((xw->flags & NATIONAL)) {
408e0a2b6dfSmrg		    chr = seven;
409e0a2b6dfSmrg		}
4102eaa94a1Schristos		if (chr == 0x23) {
4112eaa94a1Schristos		    chr = XTERM_POUND;
412e0a2b6dfSmrg#if OPT_WIDE_CHARS
413e0a2b6dfSmrg		    if (screen->utf8_nrc_mode) {
414e0a2b6dfSmrg			chr = 0xa3;
415e0a2b6dfSmrg		    }
4162eaa94a1Schristos#endif
4172eaa94a1Schristos		}
4182eaa94a1Schristos	    }
4192eaa94a1Schristos	    break;
420d522f475Smrg
421e0a2b6dfSmrg	case nrc_DEC_Alt_Chars:
422e0a2b6dfSmrg	case nrc_DEC_Alt_Graphics:
423e0a2b6dfSmrg	case nrc_ASCII:
4242eaa94a1Schristos	    break;
425d522f475Smrg
426e0a2b6dfSmrg	case nrc_DEC_Spec_Graphic:
4272eaa94a1Schristos	    if (seven > 0x5f && seven <= 0x7e) {
428d522f475Smrg#if OPT_WIDE_CHARS
429e0a2b6dfSmrg		if (screen->utf8_mode || screen->utf8_nrc_mode)
430f2e35a3aSmrg		    chr = (int) dec2ucs(screen, (unsigned) (seven - 0x5f));
4312eaa94a1Schristos		else
432d522f475Smrg#endif
4332eaa94a1Schristos		    chr = seven - 0x5f;
434f2e35a3aSmrg	    } else if (chr == 0x5f) {
435f2e35a3aSmrg		chr = 0;
4362eaa94a1Schristos	    } else {
4372eaa94a1Schristos		chr = seven;
4382eaa94a1Schristos	    }
4392eaa94a1Schristos	    break;
4402eaa94a1Schristos
441e0a2b6dfSmrg	case nrc_DEC_Supp:
442e0a2b6dfSmrg	case nrc_DEC_Supp_Graphic:
44304b94745Smrg	    map_DEC_Supp_Graphic(chr = seven, chr = eight);
4442eaa94a1Schristos	    break;
4452eaa94a1Schristos
446e0a2b6dfSmrg	case nrc_DEC_Technical:
447f2e35a3aSmrg	    map_DEC_Technical(chr = seven);
4482eaa94a1Schristos	    break;
4492eaa94a1Schristos
450e0a2b6dfSmrg	case nrc_Dutch:
451e0a2b6dfSmrg	    map_NRCS_Dutch(chr = seven);
4522eaa94a1Schristos	    break;
4532eaa94a1Schristos
454e0a2b6dfSmrg	case nrc_Finnish:
455e0a2b6dfSmrg	case nrc_Finnish2:
456e0a2b6dfSmrg	    map_NRCS_Finnish(chr = seven);
4572eaa94a1Schristos	    break;
4582eaa94a1Schristos
459e0a2b6dfSmrg	case nrc_French:
460e0a2b6dfSmrg	case nrc_French2:
461e0a2b6dfSmrg	    map_NRCS_French(chr = seven);
4622eaa94a1Schristos	    break;
4632eaa94a1Schristos
464e0a2b6dfSmrg	case nrc_French_Canadian:
465e0a2b6dfSmrg	case nrc_French_Canadian2:
466e0a2b6dfSmrg	    map_NRCS_French_Canadian(chr = seven);
4672eaa94a1Schristos	    break;
4682eaa94a1Schristos
469e0a2b6dfSmrg	case nrc_German:
470e0a2b6dfSmrg	    map_NRCS_German(chr = seven);
4712eaa94a1Schristos	    break;
4722eaa94a1Schristos
473f2e35a3aSmrg	case nrc_Greek:
474f2e35a3aSmrg	    map_NRCS_Greek(chr = seven);	/* FIXME - ELOT? */
475f2e35a3aSmrg	    break;
476f2e35a3aSmrg
477f2e35a3aSmrg	case nrc_DEC_Greek_Supp:
478f2e35a3aSmrg	    map_DEC_Greek_Supp(chr = seven);
479f2e35a3aSmrg	    break;
480f2e35a3aSmrg
481f2e35a3aSmrg	case nrc_ISO_Greek_Supp:
482f2e35a3aSmrg	    map_ISO_Greek_Supp(chr = seven);
483f2e35a3aSmrg	    break;
484f2e35a3aSmrg
485f2e35a3aSmrg	case nrc_DEC_Hebrew_Supp:
486f2e35a3aSmrg	    map_DEC_Hebrew_Supp(chr = seven);
487f2e35a3aSmrg	    break;
488f2e35a3aSmrg
489e0a2b6dfSmrg	case nrc_Hebrew:
490f2e35a3aSmrg	    map_NRCS_Hebrew(chr = seven);
491f2e35a3aSmrg	    break;
492f2e35a3aSmrg
493f2e35a3aSmrg	case nrc_ISO_Hebrew_Supp:
494f2e35a3aSmrg	    map_ISO_Hebrew(chr = seven);
4952eaa94a1Schristos	    break;
4962eaa94a1Schristos
497e0a2b6dfSmrg	case nrc_Italian:
498e0a2b6dfSmrg	    map_NRCS_Italian(chr = seven);
499e0a2b6dfSmrg	    break;
500e0a2b6dfSmrg
501f2e35a3aSmrg	case nrc_ISO_Latin_2_Supp:
502f2e35a3aSmrg	    map_ISO_Latin_2(chr = seven);
503f2e35a3aSmrg	    break;
504f2e35a3aSmrg
505f2e35a3aSmrg	case nrc_ISO_Latin_5_Supp:
506f2e35a3aSmrg	    map_ISO_Latin_5(chr = seven);
507f2e35a3aSmrg	    break;
508f2e35a3aSmrg
509f2e35a3aSmrg	case nrc_ISO_Latin_Cyrillic:
510f2e35a3aSmrg	    map_ISO_Latin_Cyrillic(chr = seven);
511f2e35a3aSmrg	    break;
512f2e35a3aSmrg
5135104ee6eSmrg	case nrc_JIS_Katakana:
5145104ee6eSmrg	    map_JIS_Katakana(chr = seven);
5155104ee6eSmrg	    break;
5165104ee6eSmrg
5175104ee6eSmrg	case nrc_JIS_Roman:
5185104ee6eSmrg	    map_JIS_Roman(chr = seven);
5195104ee6eSmrg	    break;
5205104ee6eSmrg
521e0a2b6dfSmrg	case nrc_Norwegian_Danish:
522e0a2b6dfSmrg	case nrc_Norwegian_Danish2:
523e0a2b6dfSmrg	case nrc_Norwegian_Danish3:
524e0a2b6dfSmrg	    map_NRCS_Norwegian_Danish(chr = seven);
525e0a2b6dfSmrg	    break;
526e0a2b6dfSmrg
527e0a2b6dfSmrg	case nrc_Portugese:
528e0a2b6dfSmrg	    map_NRCS_Portuguese(chr = seven);
529e0a2b6dfSmrg	    break;
530e0a2b6dfSmrg
5315104ee6eSmrg	case nrc_Russian:
5325104ee6eSmrg	    map_NRCS_Russian(chr = seven);
5335104ee6eSmrg	    break;
5345104ee6eSmrg
53504b94745Smrg	case nrc_SCS_NRCS:	/* vt5xx - Serbo/Croatian */
5365104ee6eSmrg	    map_NRCS_Serbo_Croatian(chr = seven);
537e0a2b6dfSmrg	    break;
538e0a2b6dfSmrg
539e0a2b6dfSmrg	case nrc_Spanish:
540e0a2b6dfSmrg	    map_NRCS_Spanish(chr = seven);
541e0a2b6dfSmrg	    break;
542e0a2b6dfSmrg
543e0a2b6dfSmrg	case nrc_Swedish2:
544e0a2b6dfSmrg	case nrc_Swedish:
545e0a2b6dfSmrg	    map_NRCS_Swedish(chr = seven);
546e0a2b6dfSmrg	    break;
547e0a2b6dfSmrg
548e0a2b6dfSmrg	case nrc_Swiss:
549e0a2b6dfSmrg	    map_NRCS_Swiss(chr = seven);
550e0a2b6dfSmrg	    break;
551e0a2b6dfSmrg
552e0a2b6dfSmrg	case nrc_Turkish:
553f2e35a3aSmrg	    map_NRCS_Turkish(chr = seven);
5542eaa94a1Schristos	    break;
5552eaa94a1Schristos
556f2e35a3aSmrg	case nrc_DEC_Turkish_Supp:
557f2e35a3aSmrg	    map_DEC_Turkish_Supp(chr = seven);
558f2e35a3aSmrg	    break;
559f2e35a3aSmrg
560f2e35a3aSmrg	case nrc_DEC_Cyrillic:
561f2e35a3aSmrg	    map_DEC_Cyrillic(chr = seven);
562f2e35a3aSmrg	    break;
563f2e35a3aSmrg
564f2e35a3aSmrg	case nrc_Unknown:
5652eaa94a1Schristos	default:		/* any character sets we don't recognize */
5662eaa94a1Schristos	    break;
567d522f475Smrg	}
5682eaa94a1Schristos	/*
5692eaa94a1Schristos	 * The state machine already treated DEL as a nonprinting and
570f2e35a3aSmrg	 * nonspacing character.  If we have DEL now, remove it.
5712eaa94a1Schristos	 */
57204b94745Smrg	if (chr == ANSI_DEL && isSevenBit(cs)) {
573f2e35a3aSmrg	    IChar *s1;
574f2e35a3aSmrg	    --ptr;
575f2e35a3aSmrg	    for (s1 = s; s1 < ptr; ++s1) {
576f2e35a3aSmrg		s1[0] = s1[1];
577f2e35a3aSmrg	    }
57804b94745Smrg	    --count;
57904b94745Smrg#if OPT_DEC_RECTOPS
58004b94745Smrg	    --sums;
58104b94745Smrg#endif
582f2e35a3aSmrg	} else {
58304b94745Smrg	    if (eight >= 128 && chr < 128 && chr > 32)
58404b94745Smrg		chr |= 128;
5855104ee6eSmrg	    *s = (IChar) chr;
586f2e35a3aSmrg	}
5872eaa94a1Schristos    }
5882eaa94a1Schristos    TRACE(("%d\t%s\n",
5892eaa94a1Schristos	   count,
59004b94745Smrg	   visibleIChars(buf, (size_t) length)));
5912eaa94a1Schristos    return count;
5922eaa94a1Schristos#undef MAP
593e0a2b6dfSmrg#undef UNI
594e0a2b6dfSmrg#undef XXX
595d522f475Smrg}
59604b94745Smrg
59704b94745Smrg#if OPT_DEC_RECTOPS
59804b94745Smrg/*
59904b94745Smrg * Given a mapped character, e.g., a Unicode value returned by xtermCharSetIn,
60004b94745Smrg * match it against the current GL/GR selection and return the corresponding
60104b94745Smrg * DEC internal character-set code for DECRQCRA.
60204b94745Smrg *
60304b94745Smrg * A hardware terminal presumably stores the original and mapped characters,
60404b94745Smrg * as well as the character set which was selected at that time  Doing that
60504b94745Smrg * in xterm adds a couple of bytes to every cell.
60604b94745Smrg */
60704b94745Smrgint
60804b94745SmrgxtermCharSetDec(XtermWidget xw, IChar chr, DECNRCM_codes cs)
60904b94745Smrg{
61004b94745Smrg#define MAP(from, to) case from: result = to; break;
61104b94745Smrg
61204b94745Smrg#define DFTMAP()      result = (actual | 0x80)
61304b94745Smrg#define DFT_94(chr)   result = ((actual) & 0x7f)
61404b94745Smrg#define DFT_96(chr)   result = ((actual) | 0x80)
61504b94745Smrg
61604b94745Smrg#if OPT_WIDE_CHARS
61704b94745Smrg#define UNI(from, to) case from: if (screen->utf8_nrc_mode) result = to; break;
61804b94745Smrg#define XXX(from, to) UNI(from, to)
61904b94745Smrg#else
62004b94745Smrg#define UNI(old, new) case new: result = old; break;
62104b94745Smrg#define XXX(from, to)		/* nothing */
62204b94745Smrg#endif
62304b94745Smrg
62404b94745Smrg    int result;
62504b94745Smrg
62604b94745Smrg    if (chr < 0x20
62704b94745Smrg#if OPT_WIDE_CHARS
62804b94745Smrg	|| chr > 0xff
62904b94745Smrg#endif
63004b94745Smrg	) {
63104b94745Smrg	result = ANSI_ESC;
63204b94745Smrg    } else {
63304b94745Smrg	Boolean isSeven = isSevenBit(cs);
63404b94745Smrg	TScreen *screen = TScreenOf(xw);
63504b94745Smrg
63604b94745Smrg	result = -1;
63704b94745Smrg
63804b94745Smrg	HandleUPSS(cs);
63904b94745Smrg
64004b94745Smrg	if (chr == 0xa0 && isSeven) {
64104b94745Smrg	    result = ANSI_ESC;
64204b94745Smrg	} else if (chr == ANSI_SPA && isSeven) {
64304b94745Smrg	    result = ANSI_SPA;
64404b94745Smrg	} else if ((chr == ANSI_DEL || chr == 0xff) && isSeven) {
64504b94745Smrg	    result = 0;
64604b94745Smrg	} else {
64704b94745Smrg	    int actual = (int) chr;
64804b94745Smrg	    chr &= 0x7f;
64904b94745Smrg
65004b94745Smrg	    switch (cs) {
65104b94745Smrg	    case nrc_DEC_Alt_Chars:
65204b94745Smrg	    case nrc_DEC_Alt_Graphics:
65304b94745Smrg	    case nrc_ASCII:
65404b94745Smrg		result = (int) chr;
65504b94745Smrg		break;
65604b94745Smrg
65704b94745Smrg	    case nrc_British:
65804b94745Smrg		if (chr >= 0xa0 && chr < 0xff) {
65904b94745Smrg		    if (chr == 0x23)
66004b94745Smrg			chr = 0xA3;
66104b94745Smrg		    result = (int) chr;
66204b94745Smrg		}
66304b94745Smrg		break;
66404b94745Smrg
66504b94745Smrg	    case nrc_DEC_Cyrillic:
66604b94745Smrg		unmap_DEC_Cyrillic(chr, DFT_94(chr));
66704b94745Smrg		break;
66804b94745Smrg
66904b94745Smrg	    case nrc_DEC_Spec_Graphic:
67004b94745Smrg		unmap_DEC_Spec_Graphic(chr, DFT_94(chr));
67104b94745Smrg		break;
67204b94745Smrg
67304b94745Smrg	    case nrc_DEC_Supp:
67404b94745Smrg		/* FALLTHRU */
67504b94745Smrg	    case nrc_DEC_Supp_Graphic:
67604b94745Smrg		unmap_DEC_Supp_Graphic(chr, DFTMAP());
67704b94745Smrg		break;
67804b94745Smrg
67904b94745Smrg	    case nrc_DEC_Technical:
68004b94745Smrg		unmap_DEC_Technical(chr, DFTMAP());
68104b94745Smrg		break;
68204b94745Smrg
68304b94745Smrg	    case nrc_Dutch:
68404b94745Smrg		unmap_NRCS_Dutch(chr, DFT_94(chr));
68504b94745Smrg		break;
68604b94745Smrg
68704b94745Smrg	    case nrc_Finnish:
68804b94745Smrg	    case nrc_Finnish2:
68904b94745Smrg		unmap_NRCS_Finnish(chr, DFT_94(chr));
69004b94745Smrg		break;
69104b94745Smrg
69204b94745Smrg	    case nrc_French:
69304b94745Smrg	    case nrc_French2:
69404b94745Smrg		unmap_NRCS_French(chr, DFT_94(chr));
69504b94745Smrg		break;
69604b94745Smrg
69704b94745Smrg	    case nrc_French_Canadian:
69804b94745Smrg	    case nrc_French_Canadian2:
69904b94745Smrg		unmap_NRCS_French_Canadian(chr, DFT_94(chr));
70004b94745Smrg		break;
70104b94745Smrg
70204b94745Smrg	    case nrc_German:
70304b94745Smrg		unmap_NRCS_German(chr, DFT_94(chr));
70404b94745Smrg		break;
70504b94745Smrg
70604b94745Smrg	    case nrc_Greek:
70704b94745Smrg		unmap_NRCS_Greek(chr, DFT_94(chr));
70804b94745Smrg		break;
70904b94745Smrg
71004b94745Smrg	    case nrc_DEC_Greek_Supp:
71104b94745Smrg		unmap_DEC_Greek_Supp(chr, DFTMAP());
71204b94745Smrg		break;
71304b94745Smrg
71404b94745Smrg	    case nrc_ISO_Greek_Supp:
71504b94745Smrg		unmap_ISO_Greek_Supp(chr, DFTMAP());
71604b94745Smrg		break;
71704b94745Smrg
71804b94745Smrg	    case nrc_DEC_Hebrew_Supp:
71904b94745Smrg		unmap_DEC_Hebrew_Supp(chr, DFTMAP());
72004b94745Smrg		break;
72104b94745Smrg
72204b94745Smrg	    case nrc_Hebrew:
72304b94745Smrg		unmap_NRCS_Hebrew(chr, DFT_94(chr));
72404b94745Smrg		break;
72504b94745Smrg
72604b94745Smrg	    case nrc_ISO_Hebrew_Supp:
72704b94745Smrg		unmap_ISO_Hebrew(chr, DFTMAP());
72804b94745Smrg		break;
72904b94745Smrg
73004b94745Smrg	    case nrc_Italian:
73104b94745Smrg		unmap_NRCS_Italian(chr, DFT_94(chr));
73204b94745Smrg		break;
73304b94745Smrg
7345104ee6eSmrg	    case nrc_JIS_Katakana:
7355104ee6eSmrg		unmap_JIS_Katakana(chr, DFT_94(chr));
7365104ee6eSmrg		break;
7375104ee6eSmrg
7385104ee6eSmrg	    case nrc_JIS_Roman:
7395104ee6eSmrg		unmap_JIS_Roman(chr, DFT_94(chr));
7405104ee6eSmrg		break;
7415104ee6eSmrg
74204b94745Smrg	    case nrc_ISO_Latin_1_Supp:
74304b94745Smrg		unmap_ISO_Latin_1(chr, DFTMAP());
74404b94745Smrg		break;
74504b94745Smrg
74604b94745Smrg	    case nrc_ISO_Latin_2_Supp:
74704b94745Smrg		unmap_ISO_Latin_2(chr, DFTMAP());
74804b94745Smrg		break;
74904b94745Smrg
75004b94745Smrg	    case nrc_ISO_Latin_5_Supp:
75104b94745Smrg		unmap_ISO_Latin_5(chr, DFTMAP());
75204b94745Smrg		break;
75304b94745Smrg
75404b94745Smrg	    case nrc_ISO_Latin_Cyrillic:
75504b94745Smrg		unmap_ISO_Latin_Cyrillic(chr, DFTMAP());
75604b94745Smrg		break;
75704b94745Smrg
75804b94745Smrg	    case nrc_Norwegian_Danish:
75904b94745Smrg	    case nrc_Norwegian_Danish2:
76004b94745Smrg	    case nrc_Norwegian_Danish3:
76104b94745Smrg		unmap_NRCS_Norwegian_Danish(chr, DFT_94(chr));
76204b94745Smrg		break;
76304b94745Smrg
76404b94745Smrg	    case nrc_Portugese:
76504b94745Smrg		unmap_NRCS_Portuguese(chr, DFT_94(chr));
76604b94745Smrg		break;
76704b94745Smrg
7685104ee6eSmrg	    case nrc_Russian:
7695104ee6eSmrg		unmap_NRCS_Russian(chr, DFT_94(chr));
7705104ee6eSmrg		break;
7715104ee6eSmrg
7725104ee6eSmrg	    case nrc_SCS_NRCS:
7735104ee6eSmrg		unmap_NRCS_Serbo_Croatian(chr, DFT_94(chr));
7745104ee6eSmrg		break;
7755104ee6eSmrg
77604b94745Smrg	    case nrc_Spanish:
77704b94745Smrg		unmap_NRCS_Spanish(chr, DFT_94(chr));
77804b94745Smrg		break;
77904b94745Smrg
78004b94745Smrg	    case nrc_Swedish:
78104b94745Smrg	    case nrc_Swedish2:
78204b94745Smrg		unmap_NRCS_Swedish(chr, DFT_94(chr));
78304b94745Smrg		break;
78404b94745Smrg
78504b94745Smrg	    case nrc_Swiss:
78604b94745Smrg		unmap_NRCS_Swiss(chr, DFT_94(chr));
78704b94745Smrg		break;
78804b94745Smrg
78904b94745Smrg	    case nrc_DEC_Turkish_Supp:
79004b94745Smrg		unmap_DEC_Turkish_Supp(chr, DFTMAP());
79104b94745Smrg		break;
79204b94745Smrg
79304b94745Smrg	    case nrc_Turkish:
79404b94745Smrg		unmap_NRCS_Turkish(chr, DFT_94(chr));
79504b94745Smrg		break;
79604b94745Smrg
79704b94745Smrg	    case nrc_British_Latin_1:
79804b94745Smrg	    case nrc_Unknown:
79904b94745Smrg	    case nrc_DEC_UPSS:
80004b94745Smrg	    default:		/* anything we cannot unmap */
80104b94745Smrg		break;
80204b94745Smrg	    }
80304b94745Smrg	    if (result < 0) {
80404b94745Smrg		if (isSeven) {
80504b94745Smrg		    DFT_94(chr);
80604b94745Smrg		} else {
80704b94745Smrg		    DFT_96(chr);
80804b94745Smrg		}
80904b94745Smrg	    }
81004b94745Smrg	}
81104b94745Smrg    }
81204b94745Smrg    return result;
81304b94745Smrg#undef MAP
81404b94745Smrg#undef UNI
81504b94745Smrg#undef XXX
81604b94745Smrg}
81704b94745Smrg#endif /* OPT_DEC_RECTOPS */
818