charsets.c revision 5104ee6e
1/* $XTermId: charsets.c,v 1.129 2024/10/03 22:21:32 tom Exp $ */
2
3/*
4 * Copyright 1998-2023,2024 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 <assert.h>
35#include <X11/keysym.h>
36
37#include <xterm.h>
38#include <data.h>
39#include <charsets.h>
40#include <fontutils.h>
41
42/*
43 * This module performs translation as needed to support the DEC VT220 national
44 * replacement character sets as well as supplementary character sets (aka
45 * code-pages) introduced in VT320, etc.
46 *
47 * We assume that xterm's font is based on the ISO 8859-1 (Latin 1) character
48 * set, which is almost the same as the DEC multinational character set.  Glyph
49 * positions 0-31 have to be the DEC graphic characters, though.
50 *
51 * References:
52 *	"VT220 Programmer Pocket Guide" EK-VT220-HR-002 (2nd ed., 1984), which
53 *		contains character charts for the national character sets.
54 *	"VT330/VT340 Programmer Reference Manual Volume 1: Text Programming"
55 *		EK-VT3XX-TP-001 (1st ed, 1987), which contains a table (2-1)
56 *		listing the glyphs which are mapped from the multinational
57 *		character set to the national character set.
58 *
59 * The latter reference, though easier to read, has a few errors and omissions.
60 */
61
62#define HandleUPSS(charset) \
63    if (charset == nrc_DEC_UPSS) { \
64	charset = screen->gsets_upss; \
65	if (screen->vtXX_level >= 5) { \
66	    /* EMPTY */ ; \
67	} else if (screen->vtXX_level >= 3) { \
68	    if (charset != nrc_DEC_Supp) \
69		charset = nrc_ISO_Latin_1_Supp; \
70	} else if (screen->vtXX_level < 2) { \
71	    charset = nrc_ASCII; \
72	} \
73    }
74
75static Boolean
76isSevenBit(DECNRCM_codes cs)
77{
78    Boolean result = False;
79
80    switch (cs) {
81    case nrc_ISO_Greek_Supp:
82    case nrc_ISO_Hebrew_Supp:
83    case nrc_ISO_Latin_1_Supp:
84    case nrc_ISO_Latin_2_Supp:
85    case nrc_ISO_Latin_5_Supp:
86    case nrc_ISO_Latin_Cyrillic:
87    case nrc_DEC_UPSS:
88	break;
89	/* VT100 character sets */
90    case nrc_ASCII:
91    case nrc_British:
92    case nrc_DEC_Alt_Chars:
93    case nrc_DEC_Spec_Graphic:
94	/* VT220 character sets */
95    case nrc_DEC_Alt_Graphics:
96    case nrc_DEC_Supp:
97	/* VT320 character sets */
98    case nrc_DEC_Supp_Graphic:
99    case nrc_DEC_Technical:
100	/* NRCS character sets (VT320 to VT520) */
101    case nrc_British_Latin_1:
102    case nrc_Dutch:
103    case nrc_Finnish2:
104    case nrc_Finnish:
105    case nrc_French2:
106    case nrc_French:
107    case nrc_French_Canadian2:
108    case nrc_French_Canadian:
109    case nrc_German:
110    case nrc_Greek:
111    case nrc_Hebrew:
112    case nrc_Italian:
113    case nrc_JIS_Katakana:
114    case nrc_JIS_Roman:
115    case nrc_Norwegian_Danish2:
116    case nrc_Norwegian_Danish3:
117    case nrc_Norwegian_Danish:
118    case nrc_Portugese:
119    case nrc_Russian:
120    case nrc_SCS_NRCS:
121    case nrc_Spanish:
122    case nrc_Swedish2:
123    case nrc_Swedish:
124    case nrc_Swiss:
125    case nrc_Turkish:
126	/* other DEC character sets */
127    case nrc_DEC_Cyrillic:
128    case nrc_DEC_Greek_Supp:
129    case nrc_DEC_Hebrew_Supp:
130    case nrc_DEC_Turkish_Supp:
131	result = True;
132	break;
133    case nrc_Unknown:
134	break;
135    }
136    return result;
137}
138
139/*
140 * Translate an input keysym to the corresponding NRC keysym.
141 */
142unsigned
143xtermCharSetIn(XtermWidget xw, unsigned code, DECNRCM_codes charset)
144{
145    TScreen *screen = TScreenOf(xw);
146#define MAP(to, from) case from: code = to; break;
147
148#if OPT_WIDE_CHARS
149#define UNI(to, from) case from: if (screen->utf8_nrc_mode) code = to; break;
150#else
151#define UNI(to, from) case from: break;
152#endif
153
154#define XXX(to, from)		/* no defined mapping to 0..255 */
155
156    TRACE(("CHARSET-IN GL=%s(G%d) GR=%s(G%d) SS%d\n\t%s\n",
157	   visibleScsCode(screen->gsets[screen->curgl]), screen->curgl,
158	   visibleScsCode(screen->gsets[screen->curgr]), screen->curgr,
159	   screen->curss,
160	   visibleUChar(code)));
161
162    HandleUPSS(charset);
163
164    switch (charset) {
165    case nrc_British:		/* United Kingdom set (or Latin 1)      */
166	if (code == XK_sterling)
167	    code = 0x23;
168	code &= 0x7f;
169	break;
170
171    case nrc_DEC_Alt_Chars:
172    case nrc_DEC_Alt_Graphics:
173    case nrc_ASCII:
174	break;
175
176    case nrc_DEC_Spec_Graphic:
177	break;
178
179    case nrc_DEC_Supp:
180	map_DEC_Supp_Graphic(code, code &= 0x7f);
181	break;
182
183    case nrc_DEC_Supp_Graphic:
184	map_DEC_Supp_Graphic(code, code |= 0x80);
185	break;
186
187    case nrc_DEC_Technical:
188	map_DEC_Technical(code);
189	break;
190
191    case nrc_Dutch:
192	map_NRCS_Dutch(code);
193	break;
194
195    case nrc_Finnish:
196    case nrc_Finnish2:
197	map_NRCS_Finnish(code);
198	break;
199
200    case nrc_French:
201    case nrc_French2:
202	map_NRCS_French(code);
203	break;
204
205    case nrc_French_Canadian:
206	map_NRCS_French_Canadian(code);
207	break;
208
209    case nrc_German:
210	map_NRCS_German(code);
211	break;
212
213    case nrc_Greek:
214	map_NRCS_Greek(code);	/* FIXME - ELOT? */
215	break;
216
217    case nrc_DEC_Greek_Supp:
218	map_DEC_Greek_Supp(code);
219	break;
220
221    case nrc_ISO_Greek_Supp:
222	map_ISO_Greek_Supp(code);
223	break;
224
225    case nrc_DEC_Hebrew_Supp:
226	map_DEC_Hebrew_Supp(code);
227	break;
228
229    case nrc_Hebrew:
230	map_NRCS_Hebrew(code);
231	break;
232
233    case nrc_ISO_Hebrew_Supp:
234	map_ISO_Hebrew(code);
235	break;
236
237    case nrc_Italian:
238	map_NRCS_Italian(code);
239	break;
240
241    case nrc_ISO_Latin_2_Supp:
242	map_ISO_Latin_2(code);
243	break;
244
245    case nrc_ISO_Latin_5_Supp:
246	map_ISO_Latin_5(code);
247	break;
248
249    case nrc_ISO_Latin_Cyrillic:
250	map_ISO_Latin_Cyrillic(code);
251	break;
252
253    case nrc_JIS_Katakana:
254	map_JIS_Katakana(code);
255	break;
256
257    case nrc_JIS_Roman:
258	map_JIS_Roman(code);
259	break;
260
261    case nrc_Norwegian_Danish:
262    case nrc_Norwegian_Danish2:
263    case nrc_Norwegian_Danish3:
264	map_NRCS_Norwegian_Danish(code);
265	break;
266
267    case nrc_Portugese:
268	map_NRCS_Portuguese(code);
269	break;
270
271    case nrc_Russian:
272	map_NRCS_Russian(code);
273	break;
274
275    case nrc_SCS_NRCS:		/* vt5xx - Serbo/Croatian */
276	map_NRCS_Serbo_Croatian(code);
277	break;
278
279    case nrc_Spanish:
280	map_NRCS_Spanish(code);
281	break;
282
283    case nrc_Swedish2:
284    case nrc_Swedish:
285	map_NRCS_Swedish(code);
286	break;
287
288    case nrc_Swiss:
289	map_NRCS_Swiss(code);
290	break;
291
292    case nrc_Turkish:
293	map_NRCS_Turkish(code);
294	break;
295
296    case nrc_DEC_Turkish_Supp:
297	map_DEC_Turkish_Supp(code);
298	break;
299
300    case nrc_DEC_Cyrillic:
301	map_DEC_Cyrillic(code);
302	break;
303
304    case nrc_ISO_Latin_1_Supp:
305    case nrc_British_Latin_1:
306    case nrc_French_Canadian2:
307    case nrc_Unknown:
308    case nrc_DEC_UPSS:
309    default:			/* any character sets we don't recognize */
310	break;
311    }
312    code &= 0x7f;		/* NRC in any case is 7-bit */
313    TRACE(("->\t%s\n",
314	   visibleUChar(code)));
315    return code;
316#undef MAP
317#undef UNI
318#undef XXX
319}
320
321/*
322 * Translate a string to the display form.  This assumes the font has the
323 * DEC graphic characters in cells 0-31, and otherwise is ISO-8859-1.
324 */
325Cardinal
326xtermCharSetOut(XtermWidget xw, Cardinal length, DECNRCM_codes leftset)
327{
328    IChar *buf = xw->work.write_text;
329    IChar *ptr = buf + length;
330    IChar *s;
331    TScreen *screen = TScreenOf(xw);
332    Cardinal count = 0;
333    DECNRCM_codes rightset = screen->gsets[(int) (screen->curgr)];
334#if OPT_DEC_RECTOPS
335    int sums = 0;
336#endif
337
338#define MAP(from, to) case from: chr = to; break;
339
340#if OPT_WIDE_CHARS
341#define UNI(from, to) case from: if (screen->utf8_nrc_mode) chr = to; break;
342#define XXX(from, to) UNI(from, to)
343#else
344#define UNI(old, new) case new: chr = old; break;
345#define XXX(from, to)		/* nothing */
346#endif
347
348    TRACE(("CHARSET-OUT GL=%s(G%d) GR=%s(G%d) SS%d\n\t%s\n",
349	   visibleScsCode(leftset), screen->curgl,
350	   visibleScsCode(rightset), screen->curgr,
351	   screen->curss,
352	   visibleIChars(buf, (size_t) length)));
353
354    assert(length != 0);
355#if OPT_DEC_RECTOPS
356    if (length != 0 && length > xw->work.sizeof_sums) {
357	xw->work.sizeof_sums += length + 80;
358	xw->work.buffer_sums = realloc(xw->work.buffer_sums,
359				       xw->work.sizeof_sums);
360	xw->work.buffer_sets = realloc(xw->work.buffer_sets,
361				       xw->work.sizeof_sums);
362    }
363    xw->work.write_sums = xw->work.buffer_sums;
364#endif
365
366    for (s = buf; s < ptr; ++s) {
367	int eight = CharOf(*s);
368	int seven = eight & 0x7f;
369	DECNRCM_codes cs = (eight >= 128) ? rightset : leftset;
370	int chr = eight;
371
372	HandleUPSS(cs);
373
374#if OPT_DEC_RECTOPS
375	if (xw->work.buffer_sums != NULL && xw->work.buffer_sets != NULL) {
376	    xw->work.buffer_sums[sums] = (Char) ((eight < 32 || eight > 255)
377						 ? ANSI_ESC
378						 : eight);
379	    xw->work.buffer_sets[sums] = cs;
380	    ++sums;
381	}
382#endif
383	count++;
384#if OPT_WIDE_CHARS
385	/*
386	 * This is only partly right - prevent inadvertent remapping of
387	 * the replacement character and other non-8bit codes into bogus
388	 * 8bit codes.
389	 */
390	if (screen->utf8_mode || screen->utf8_nrc_mode) {
391	    if (*s > 255)
392		continue;
393	}
394#endif
395	if (*s < 32)
396	    continue;
397
398	switch (cs) {
399	case nrc_DEC_UPSS:
400	    break;
401
402	case nrc_ISO_Latin_1_Supp:
403	case nrc_British_Latin_1:
404	case nrc_British:	/* United Kingdom set (or Latin 1)      */
405	    if ((xw->flags & NATIONAL)
406		|| (screen->vtXX_level <= 1)) {
407		if ((xw->flags & NATIONAL)) {
408		    chr = seven;
409		}
410		if (chr == 0x23) {
411		    chr = XTERM_POUND;
412#if OPT_WIDE_CHARS
413		    if (screen->utf8_nrc_mode) {
414			chr = 0xa3;
415		    }
416#endif
417		}
418	    }
419	    break;
420
421	case nrc_DEC_Alt_Chars:
422	case nrc_DEC_Alt_Graphics:
423	case nrc_ASCII:
424	    break;
425
426	case nrc_DEC_Spec_Graphic:
427	    if (seven > 0x5f && seven <= 0x7e) {
428#if OPT_WIDE_CHARS
429		if (screen->utf8_mode || screen->utf8_nrc_mode)
430		    chr = (int) dec2ucs(screen, (unsigned) (seven - 0x5f));
431		else
432#endif
433		    chr = seven - 0x5f;
434	    } else if (chr == 0x5f) {
435		chr = 0;
436	    } else {
437		chr = seven;
438	    }
439	    break;
440
441	case nrc_DEC_Supp:
442	case nrc_DEC_Supp_Graphic:
443	    map_DEC_Supp_Graphic(chr = seven, chr = eight);
444	    break;
445
446	case nrc_DEC_Technical:
447	    map_DEC_Technical(chr = seven);
448	    break;
449
450	case nrc_Dutch:
451	    map_NRCS_Dutch(chr = seven);
452	    break;
453
454	case nrc_Finnish:
455	case nrc_Finnish2:
456	    map_NRCS_Finnish(chr = seven);
457	    break;
458
459	case nrc_French:
460	case nrc_French2:
461	    map_NRCS_French(chr = seven);
462	    break;
463
464	case nrc_French_Canadian:
465	case nrc_French_Canadian2:
466	    map_NRCS_French_Canadian(chr = seven);
467	    break;
468
469	case nrc_German:
470	    map_NRCS_German(chr = seven);
471	    break;
472
473	case nrc_Greek:
474	    map_NRCS_Greek(chr = seven);	/* FIXME - ELOT? */
475	    break;
476
477	case nrc_DEC_Greek_Supp:
478	    map_DEC_Greek_Supp(chr = seven);
479	    break;
480
481	case nrc_ISO_Greek_Supp:
482	    map_ISO_Greek_Supp(chr = seven);
483	    break;
484
485	case nrc_DEC_Hebrew_Supp:
486	    map_DEC_Hebrew_Supp(chr = seven);
487	    break;
488
489	case nrc_Hebrew:
490	    map_NRCS_Hebrew(chr = seven);
491	    break;
492
493	case nrc_ISO_Hebrew_Supp:
494	    map_ISO_Hebrew(chr = seven);
495	    break;
496
497	case nrc_Italian:
498	    map_NRCS_Italian(chr = seven);
499	    break;
500
501	case nrc_ISO_Latin_2_Supp:
502	    map_ISO_Latin_2(chr = seven);
503	    break;
504
505	case nrc_ISO_Latin_5_Supp:
506	    map_ISO_Latin_5(chr = seven);
507	    break;
508
509	case nrc_ISO_Latin_Cyrillic:
510	    map_ISO_Latin_Cyrillic(chr = seven);
511	    break;
512
513	case nrc_JIS_Katakana:
514	    map_JIS_Katakana(chr = seven);
515	    break;
516
517	case nrc_JIS_Roman:
518	    map_JIS_Roman(chr = seven);
519	    break;
520
521	case nrc_Norwegian_Danish:
522	case nrc_Norwegian_Danish2:
523	case nrc_Norwegian_Danish3:
524	    map_NRCS_Norwegian_Danish(chr = seven);
525	    break;
526
527	case nrc_Portugese:
528	    map_NRCS_Portuguese(chr = seven);
529	    break;
530
531	case nrc_Russian:
532	    map_NRCS_Russian(chr = seven);
533	    break;
534
535	case nrc_SCS_NRCS:	/* vt5xx - Serbo/Croatian */
536	    map_NRCS_Serbo_Croatian(chr = seven);
537	    break;
538
539	case nrc_Spanish:
540	    map_NRCS_Spanish(chr = seven);
541	    break;
542
543	case nrc_Swedish2:
544	case nrc_Swedish:
545	    map_NRCS_Swedish(chr = seven);
546	    break;
547
548	case nrc_Swiss:
549	    map_NRCS_Swiss(chr = seven);
550	    break;
551
552	case nrc_Turkish:
553	    map_NRCS_Turkish(chr = seven);
554	    break;
555
556	case nrc_DEC_Turkish_Supp:
557	    map_DEC_Turkish_Supp(chr = seven);
558	    break;
559
560	case nrc_DEC_Cyrillic:
561	    map_DEC_Cyrillic(chr = seven);
562	    break;
563
564	case nrc_Unknown:
565	default:		/* any character sets we don't recognize */
566	    break;
567	}
568	/*
569	 * The state machine already treated DEL as a nonprinting and
570	 * nonspacing character.  If we have DEL now, remove it.
571	 */
572	if (chr == ANSI_DEL && isSevenBit(cs)) {
573	    IChar *s1;
574	    --ptr;
575	    for (s1 = s; s1 < ptr; ++s1) {
576		s1[0] = s1[1];
577	    }
578	    --count;
579#if OPT_DEC_RECTOPS
580	    --sums;
581#endif
582	} else {
583	    if (eight >= 128 && chr < 128 && chr > 32)
584		chr |= 128;
585	    *s = (IChar) chr;
586	}
587    }
588    TRACE(("%d\t%s\n",
589	   count,
590	   visibleIChars(buf, (size_t) length)));
591    return count;
592#undef MAP
593#undef UNI
594#undef XXX
595}
596
597#if OPT_DEC_RECTOPS
598/*
599 * Given a mapped character, e.g., a Unicode value returned by xtermCharSetIn,
600 * match it against the current GL/GR selection and return the corresponding
601 * DEC internal character-set code for DECRQCRA.
602 *
603 * A hardware terminal presumably stores the original and mapped characters,
604 * as well as the character set which was selected at that time  Doing that
605 * in xterm adds a couple of bytes to every cell.
606 */
607int
608xtermCharSetDec(XtermWidget xw, IChar chr, DECNRCM_codes cs)
609{
610#define MAP(from, to) case from: result = to; break;
611
612#define DFTMAP()      result = (actual | 0x80)
613#define DFT_94(chr)   result = ((actual) & 0x7f)
614#define DFT_96(chr)   result = ((actual) | 0x80)
615
616#if OPT_WIDE_CHARS
617#define UNI(from, to) case from: if (screen->utf8_nrc_mode) result = to; break;
618#define XXX(from, to) UNI(from, to)
619#else
620#define UNI(old, new) case new: result = old; break;
621#define XXX(from, to)		/* nothing */
622#endif
623
624    int result;
625
626    if (chr < 0x20
627#if OPT_WIDE_CHARS
628	|| chr > 0xff
629#endif
630	) {
631	result = ANSI_ESC;
632    } else {
633	Boolean isSeven = isSevenBit(cs);
634	TScreen *screen = TScreenOf(xw);
635
636	result = -1;
637
638	HandleUPSS(cs);
639
640	if (chr == 0xa0 && isSeven) {
641	    result = ANSI_ESC;
642	} else if (chr == ANSI_SPA && isSeven) {
643	    result = ANSI_SPA;
644	} else if ((chr == ANSI_DEL || chr == 0xff) && isSeven) {
645	    result = 0;
646	} else {
647	    int actual = (int) chr;
648	    chr &= 0x7f;
649
650	    switch (cs) {
651	    case nrc_DEC_Alt_Chars:
652	    case nrc_DEC_Alt_Graphics:
653	    case nrc_ASCII:
654		result = (int) chr;
655		break;
656
657	    case nrc_British:
658		if (chr >= 0xa0 && chr < 0xff) {
659		    if (chr == 0x23)
660			chr = 0xA3;
661		    result = (int) chr;
662		}
663		break;
664
665	    case nrc_DEC_Cyrillic:
666		unmap_DEC_Cyrillic(chr, DFT_94(chr));
667		break;
668
669	    case nrc_DEC_Spec_Graphic:
670		unmap_DEC_Spec_Graphic(chr, DFT_94(chr));
671		break;
672
673	    case nrc_DEC_Supp:
674		/* FALLTHRU */
675	    case nrc_DEC_Supp_Graphic:
676		unmap_DEC_Supp_Graphic(chr, DFTMAP());
677		break;
678
679	    case nrc_DEC_Technical:
680		unmap_DEC_Technical(chr, DFTMAP());
681		break;
682
683	    case nrc_Dutch:
684		unmap_NRCS_Dutch(chr, DFT_94(chr));
685		break;
686
687	    case nrc_Finnish:
688	    case nrc_Finnish2:
689		unmap_NRCS_Finnish(chr, DFT_94(chr));
690		break;
691
692	    case nrc_French:
693	    case nrc_French2:
694		unmap_NRCS_French(chr, DFT_94(chr));
695		break;
696
697	    case nrc_French_Canadian:
698	    case nrc_French_Canadian2:
699		unmap_NRCS_French_Canadian(chr, DFT_94(chr));
700		break;
701
702	    case nrc_German:
703		unmap_NRCS_German(chr, DFT_94(chr));
704		break;
705
706	    case nrc_Greek:
707		unmap_NRCS_Greek(chr, DFT_94(chr));
708		break;
709
710	    case nrc_DEC_Greek_Supp:
711		unmap_DEC_Greek_Supp(chr, DFTMAP());
712		break;
713
714	    case nrc_ISO_Greek_Supp:
715		unmap_ISO_Greek_Supp(chr, DFTMAP());
716		break;
717
718	    case nrc_DEC_Hebrew_Supp:
719		unmap_DEC_Hebrew_Supp(chr, DFTMAP());
720		break;
721
722	    case nrc_Hebrew:
723		unmap_NRCS_Hebrew(chr, DFT_94(chr));
724		break;
725
726	    case nrc_ISO_Hebrew_Supp:
727		unmap_ISO_Hebrew(chr, DFTMAP());
728		break;
729
730	    case nrc_Italian:
731		unmap_NRCS_Italian(chr, DFT_94(chr));
732		break;
733
734	    case nrc_JIS_Katakana:
735		unmap_JIS_Katakana(chr, DFT_94(chr));
736		break;
737
738	    case nrc_JIS_Roman:
739		unmap_JIS_Roman(chr, DFT_94(chr));
740		break;
741
742	    case nrc_ISO_Latin_1_Supp:
743		unmap_ISO_Latin_1(chr, DFTMAP());
744		break;
745
746	    case nrc_ISO_Latin_2_Supp:
747		unmap_ISO_Latin_2(chr, DFTMAP());
748		break;
749
750	    case nrc_ISO_Latin_5_Supp:
751		unmap_ISO_Latin_5(chr, DFTMAP());
752		break;
753
754	    case nrc_ISO_Latin_Cyrillic:
755		unmap_ISO_Latin_Cyrillic(chr, DFTMAP());
756		break;
757
758	    case nrc_Norwegian_Danish:
759	    case nrc_Norwegian_Danish2:
760	    case nrc_Norwegian_Danish3:
761		unmap_NRCS_Norwegian_Danish(chr, DFT_94(chr));
762		break;
763
764	    case nrc_Portugese:
765		unmap_NRCS_Portuguese(chr, DFT_94(chr));
766		break;
767
768	    case nrc_Russian:
769		unmap_NRCS_Russian(chr, DFT_94(chr));
770		break;
771
772	    case nrc_SCS_NRCS:
773		unmap_NRCS_Serbo_Croatian(chr, DFT_94(chr));
774		break;
775
776	    case nrc_Spanish:
777		unmap_NRCS_Spanish(chr, DFT_94(chr));
778		break;
779
780	    case nrc_Swedish:
781	    case nrc_Swedish2:
782		unmap_NRCS_Swedish(chr, DFT_94(chr));
783		break;
784
785	    case nrc_Swiss:
786		unmap_NRCS_Swiss(chr, DFT_94(chr));
787		break;
788
789	    case nrc_DEC_Turkish_Supp:
790		unmap_DEC_Turkish_Supp(chr, DFTMAP());
791		break;
792
793	    case nrc_Turkish:
794		unmap_NRCS_Turkish(chr, DFT_94(chr));
795		break;
796
797	    case nrc_British_Latin_1:
798	    case nrc_Unknown:
799	    case nrc_DEC_UPSS:
800	    default:		/* anything we cannot unmap */
801		break;
802	    }
803	    if (result < 0) {
804		if (isSeven) {
805		    DFT_94(chr);
806		} else {
807		    DFT_96(chr);
808		}
809	    }
810	}
811    }
812    return result;
813#undef MAP
814#undef UNI
815#undef XXX
816}
817#endif /* OPT_DEC_RECTOPS */
818