charsets.c revision d522f475
1/* $XTermId: charsets.c,v 1.36 2007/03/19 23:47:00 tom Exp $ */
2
3/*
4 * $XFree86: xc/programs/xterm/charsets.c,v 1.12 2005/01/14 01:50:02 dickey Exp $
5 */
6
7/************************************************************
8
9Copyright 1998-2006,2007 by Thomas E. Dickey
10
11                        All Rights Reserved
12
13Permission is hereby granted, free of charge, to any person obtaining a
14copy of this software and associated documentation files (the
15"Software"), to deal in the Software without restriction, including
16without limitation the rights to use, copy, modify, merge, publish,
17distribute, sublicense, and/or sell copies of the Software, and to
18permit persons to whom the Software is furnished to do so, subject to
19the following conditions:
20
21The above copyright notice and this permission notice shall be included
22in all copies or substantial portions of the Software.
23
24THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
27IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
28CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
32Except as contained in this notice, the name(s) of the above copyright
33holders shall not be used in advertising or otherwise to promote the
34sale, use or other dealings in this Software without prior written
35authorization.
36
37********************************************************/
38
39#include <xterm.h>
40#include <data.h>
41#include <fontutils.h>
42
43#include <X11/keysym.h>
44
45/*
46 * This module performs translation as needed to support the DEC VT220 national
47 * replacement character sets.  We assume that xterm's font is based on the ISO
48 * 8859-1 (Latin 1) character set, which is almost the same as the DEC
49 * multinational character set.  Glyph positions 0-31 have to be the DEC
50 * graphic characters, though.
51 *
52 * References:
53 *	"VT220 Programmer Pocket Guide" EK-VT220-HR-002 (2nd ed., 1984), which
54 *		contains character charts for the national character sets.
55 *	"VT330/VT340 Programmer Reference Manual Volume 1: Text Programming"
56 *		EK-VT3XX-TP-001 (1st ed, 1987), which contains a table (2-1)
57 *		listing the glyphs which are mapped from the multinational
58 *		character set to the national character set.
59 *
60 * The latter reference, though easier to read, has a few errors and omissions.
61 */
62
63/*
64 * Translate an input keysym to the corresponding NRC keysym.
65 */
66unsigned xtermCharSetIn(unsigned code, int charset)
67{
68	if (code >= 128 && code < 256) {
69		switch (charset) {
70		case 'A':	/* United Kingdom set (or Latin 1)	*/
71			if (code == XK_sterling)
72				code = 0x23;
73			code &= 0x7f;
74			break;
75
76#if OPT_XMC_GLITCH
77		case '?':
78#endif
79		case '1':	/* Alternate Character ROM standard characters */
80		case '2':	/* Alternate Character ROM special graphics */
81		case 'B':	/* ASCII set				*/
82			break;
83
84		case '0':	/* special graphics (line drawing)	*/
85			break;
86
87		case '4':	/* Dutch */
88			switch (code) {
89			case XK_sterling:	code = 0x23;	break;
90			case XK_threequarters:	code = 0x40;	break;
91			case XK_ydiaeresis:	code = 0x5b;	break;
92			case XK_onehalf:	code = 0x5c;	break;
93	/* N/A		case XK_bar:		code = 0x5d;	break; */
94			case XK_diaeresis:	code = 0x7b;	break;
95	/* N/A		case XK_f:		code = 0x7c;	break; */
96			case XK_onequarter:	code = 0x7d;	break;
97			case XK_acute:		code = 0x7e;	break;
98			}
99			break;
100
101		case 'C':
102		case '5':	/* Finnish */
103			switch (code) {
104			case XK_Adiaeresis:	code = 0x5b;	break;
105			case XK_Odiaeresis:	code = 0x5c;	break;
106			case XK_Aring:		code = 0x5d;	break;
107			case XK_Udiaeresis:	code = 0x5e;	break;
108			case XK_eacute:		code = 0x60;	break;
109			case XK_adiaeresis:	code = 0x7b;	break;
110			case XK_odiaeresis:	code = 0x7c;	break;
111			case XK_aring:		code = 0x7d;	break;
112			case XK_udiaeresis:	code = 0x7e;	break;
113			}
114			break;
115
116		case 'R':	/* French */
117			switch (code) {
118			case XK_sterling:	code = 0x23;	break;
119			case XK_agrave:		code = 0x40;	break;
120			case XK_degree:		code = 0x5b;	break;
121			case XK_ccedilla:	code = 0x5c;	break;
122			case XK_section:	code = 0x5d;	break;
123			case XK_eacute:		code = 0x7b;	break;
124			case XK_ugrave:		code = 0x7c;	break;
125			case XK_egrave:		code = 0x7d;	break;
126			case XK_diaeresis:	code = 0x7e;	break;
127			}
128			break;
129
130		case 'Q':	/* French Canadian */
131			switch (code) {
132			case XK_agrave:		code = 0x40;	break;
133			case XK_acircumflex:	code = 0x5b;	break;
134			case XK_ccedilla:	code = 0x5c;	break;
135			case XK_ecircumflex:	code = 0x5d;	break;
136			case XK_icircumflex:	code = 0x5e;	break;
137			case XK_ocircumflex:	code = 0x60;	break;
138			case XK_eacute:		code = 0x7b;	break;
139			case XK_ugrave:		code = 0x7c;	break;
140			case XK_egrave:		code = 0x7d;	break;
141			case XK_ucircumflex:	code = 0x7e;	break;
142			}
143			break;
144
145		case 'K':	/* German */
146			switch (code) {
147			case XK_section:	code = 0x40;	break;
148			case XK_Adiaeresis:	code = 0x5b;	break;
149			case XK_Odiaeresis:	code = 0x5c;	break;
150			case XK_Udiaeresis:	code = 0x5d;	break;
151			case XK_adiaeresis:	code = 0x7b;	break;
152			case XK_odiaeresis:	code = 0x7c;	break;
153			case XK_udiaeresis:	code = 0x7d;	break;
154			case XK_ssharp:		code = 0x7e;	break;
155			}
156			break;
157
158		case 'Y':	/* Italian */
159			switch (code) {
160			case XK_sterling:	code = 0x23;	break;
161			case XK_section:	code = 0x40;	break;
162			case XK_degree:		code = 0x5b;	break;
163			case XK_ccedilla:	code = 0x5c;	break;
164			case XK_eacute:		code = 0x5d;	break;
165			case XK_ugrave:		code = 0x60;	break;
166			case XK_agrave:		code = 0x7b;	break;
167			case XK_ograve:		code = 0x7c;	break;
168			case XK_egrave:		code = 0x7d;	break;
169			case XK_igrave:		code = 0x7e;	break;
170			}
171			break;
172
173		case 'E':
174		case '6':	/* Norwegian/Danish */
175			switch (code) {
176			case XK_Adiaeresis:	code = 0x40;	break;
177			case XK_AE:		code = 0x5b;	break;
178			case XK_Ooblique:	code = 0x5c;	break;
179			case XK_Aring:		code = 0x5d;	break;
180			case XK_Udiaeresis:	code = 0x5e;	break;
181			case XK_adiaeresis:	code = 0x60;	break;
182			case XK_ae:		code = 0x7b;	break;
183			case XK_oslash:		code = 0x7c;	break;
184			case XK_aring:		code = 0x7d;	break;
185			case XK_udiaeresis:	code = 0x7e;	break;
186			}
187			break;
188
189		case 'Z':	/* Spanish */
190			switch (code) {
191			case XK_sterling:	code = 0x23;	break;
192			case XK_section:	code = 0x40;	break;
193			case XK_exclamdown:	code = 0x5b;	break;
194			case XK_Ntilde:		code = 0x5c;	break;
195			case XK_questiondown:	code = 0x5d;	break;
196			case XK_degree:		code = 0x7b;	break;
197			case XK_ntilde:		code = 0x7c;	break;
198			case XK_ccedilla:	code = 0x7d;	break;
199			}
200			break;
201
202		case 'H':
203		case '7':	/* Swedish */
204			switch (code) {
205			case XK_Eacute:		code = 0x40;	break;
206			case XK_Adiaeresis:	code = 0x5b;	break;
207			case XK_Odiaeresis:	code = 0x5c;	break;
208			case XK_Aring:		code = 0x5d;	break;
209			case XK_Udiaeresis:	code = 0x5e;	break;
210			case XK_eacute:		code = 0x60;	break;
211			case XK_adiaeresis:	code = 0x7b;	break;
212			case XK_odiaeresis:	code = 0x7c;	break;
213			case XK_aring:		code = 0x7d;	break;
214			case XK_udiaeresis:	code = 0x7e;	break;
215			}
216			break;
217
218		case '=':	/* Swiss */
219			switch (code) {
220			case XK_ugrave:		code = 0x23;	break;
221			case XK_agrave:		code = 0x40;	break;
222			case XK_eacute:		code = 0x5b;	break;
223			case XK_ccedilla:	code = 0x5c;	break;
224			case XK_ecircumflex:	code = 0x5d;	break;
225			case XK_icircumflex:	code = 0x5e;	break;
226			case XK_egrave:		code = 0x5f;	break;
227			case XK_ocircumflex:	code = 0x60;	break;
228			case XK_adiaeresis:	code = 0x7b;	break;
229			case XK_odiaeresis:	code = 0x7c;	break;
230			case XK_udiaeresis:	code = 0x7d;	break;
231			case XK_ucircumflex:	code = 0x7e;	break;
232			}
233			break;
234
235		default:	/* any character sets we don't recognize*/
236			break;
237		}
238		code &= 0x7f;	/* NRC in any case is 7-bit */
239	}
240	return code;
241}
242
243/*
244 * Translate a string to the display form.  This assumes the font has the
245 * DEC graphic characters in cells 0-31, and otherwise is ISO-8859-1.
246 */
247int xtermCharSetOut(IChar *buf, IChar *ptr, int leftset)
248{
249	IChar *s;
250	register TScreen *screen = TScreenOf(term);
251	int count = 0;
252	int rightset = screen->gsets[(int)(screen->curgr)];
253
254	TRACE(("CHARSET GL=%c(G%d) GR=%c(G%d) SS%d:%s\n",
255		leftset,  screen->curgl,
256		rightset, screen->curgr,
257		screen->curss,
258		visibleIChar(buf, (unsigned)(ptr - buf))));
259
260	for (s = buf; s < ptr; ++s) {
261		int eight = CharOf(E2A(*s));
262		int seven = eight & 0x7f;
263		int cs = (eight >= 128) ? rightset : leftset;
264		int chr = eight;
265
266		count++;
267		switch (cs) {
268		case 'A':	/* United Kingdom set (or Latin 1)	*/
269			if ((term->flags & NATIONAL)
270			 || (screen->vtXX_level <= 1)) {
271				if (chr == 0x23) {
272					chr = XTERM_POUND;	/* UK pound sign*/
273				}
274			} else {
275				chr = (seven | 0x80);
276			}
277			break;
278
279#if OPT_XMC_GLITCH
280		case '?':
281#endif
282		case '1':	/* Alternate Character ROM standard characters */
283		case '2':	/* Alternate Character ROM special graphics */
284		case 'B':	/* ASCII set				*/
285			break;
286
287		case '0':	/* special graphics (line drawing)	*/
288			if (seven > 0x5f && seven <= 0x7e) {
289#if OPT_WIDE_CHARS
290			    if (screen->utf8_mode)
291				chr = dec2ucs((unsigned)(seven - 0x5f));
292			    else
293#endif
294				chr = seven - 0x5f;
295			} else {
296			    chr = seven;
297			}
298			break;
299
300		case '4':	/* Dutch */
301			switch (chr = seven) {
302			case 0x23:	chr = XK_sterling;	break;
303			case 0x40:	chr = XK_threequarters;	break;
304			case 0x5b:	chr = XK_ydiaeresis;	break;
305			case 0x5c:	chr = XK_onehalf;	break;
306			case 0x5d:	chr = XK_bar;		break;
307			case 0x7b:	chr = XK_diaeresis;	break;
308			case 0x7c:	chr = XK_f;		break;
309			case 0x7d:	chr = XK_onequarter;	break;
310			case 0x7e:	chr = XK_acute;		break;
311			}
312			break;
313
314		case 'C':
315		case '5':	/* Finnish */
316			switch (chr = seven) {
317			case 0x5b:	chr = XK_Adiaeresis;	break;
318			case 0x5c:	chr = XK_Odiaeresis;	break;
319			case 0x5d:	chr = XK_Aring;		break;
320			case 0x5e:	chr = XK_Udiaeresis;	break;
321			case 0x60:	chr = XK_eacute;	break;
322			case 0x7b:	chr = XK_adiaeresis;	break;
323			case 0x7c:	chr = XK_odiaeresis;	break;
324			case 0x7d:	chr = XK_aring;		break;
325			case 0x7e:	chr = XK_udiaeresis;	break;
326			}
327			break;
328
329		case 'R':	/* French */
330			switch (chr = seven) {
331			case 0x23:	chr = XK_sterling;	break;
332			case 0x40:	chr = XK_agrave;	break;
333			case 0x5b:	chr = XK_degree;	break;
334			case 0x5c:	chr = XK_ccedilla;	break;
335			case 0x5d:	chr = XK_section;	break;
336			case 0x7b:	chr = XK_eacute;	break;
337			case 0x7c:	chr = XK_ugrave;	break;
338			case 0x7d:	chr = XK_egrave;	break;
339			case 0x7e:	chr = XK_diaeresis;	break;
340			}
341			break;
342
343		case 'Q':	/* French Canadian */
344			switch (chr = seven) {
345			case 0x40:	chr = XK_agrave;	break;
346			case 0x5b:	chr = XK_acircumflex;	break;
347			case 0x5c:	chr = XK_ccedilla;	break;
348			case 0x5d:	chr = XK_ecircumflex;	break;
349			case 0x5e:	chr = XK_icircumflex;	break;
350			case 0x60:	chr = XK_ocircumflex;	break;
351			case 0x7b:	chr = XK_eacute;	break;
352			case 0x7c:	chr = XK_ugrave;	break;
353			case 0x7d:	chr = XK_egrave;	break;
354			case 0x7e:	chr = XK_ucircumflex;	break;
355			}
356			break;
357
358		case 'K':	/* German */
359			switch (chr = seven) {
360			case 0x40:	chr = XK_section;	break;
361			case 0x5b:	chr = XK_Adiaeresis;	break;
362			case 0x5c:	chr = XK_Odiaeresis;	break;
363			case 0x5d:	chr = XK_Udiaeresis;	break;
364			case 0x7b:	chr = XK_adiaeresis;	break;
365			case 0x7c:	chr = XK_odiaeresis;	break;
366			case 0x7d:	chr = XK_udiaeresis;	break;
367			case 0x7e:	chr = XK_ssharp;	break;
368			}
369			break;
370
371		case 'Y':	/* Italian */
372			switch (chr = seven) {
373			case 0x23:	chr = XK_sterling;	break;
374			case 0x40:	chr = XK_section;	break;
375			case 0x5b:	chr = XK_degree;	break;
376			case 0x5c:	chr = XK_ccedilla;	break;
377			case 0x5d:	chr = XK_eacute;	break;
378			case 0x60:	chr = XK_ugrave;	break;
379			case 0x7b:	chr = XK_agrave;	break;
380			case 0x7c:	chr = XK_ograve;	break;
381			case 0x7d:	chr = XK_egrave;	break;
382			case 0x7e:	chr = XK_igrave;	break;
383			}
384			break;
385
386		case 'E':
387		case '6':	/* Norwegian/Danish */
388			switch (chr = seven) {
389			case 0x40:	chr = XK_Adiaeresis;	break;
390			case 0x5b:	chr = XK_AE;		break;
391			case 0x5c:	chr = XK_Ooblique;	break;
392			case 0x5d:	chr = XK_Aring;		break;
393			case 0x5e:	chr = XK_Udiaeresis;	break;
394			case 0x60:	chr = XK_adiaeresis;	break;
395			case 0x7b:	chr = XK_ae;		break;
396			case 0x7c:	chr = XK_oslash;	break;
397			case 0x7d:	chr = XK_aring;		break;
398			case 0x7e:	chr = XK_udiaeresis;	break;
399			}
400			break;
401
402		case 'Z':	/* Spanish */
403			switch (chr = seven) {
404			case 0x23:	chr = XK_sterling;	break;
405			case 0x40:	chr = XK_section;	break;
406			case 0x5b:	chr = XK_exclamdown;	break;
407			case 0x5c:	chr = XK_Ntilde;	break;
408			case 0x5d:	chr = XK_questiondown;	break;
409			case 0x7b:	chr = XK_degree;	break;
410			case 0x7c:	chr = XK_ntilde;	break;
411			case 0x7d:	chr = XK_ccedilla;	break;
412			}
413			break;
414
415		case 'H':
416		case '7':	/* Swedish */
417			switch (chr = seven) {
418			case 0x40:	chr = XK_Eacute;	break;
419			case 0x5b:	chr = XK_Adiaeresis;	break;
420			case 0x5c:	chr = XK_Odiaeresis;	break;
421			case 0x5d:	chr = XK_Aring;		break;
422			case 0x5e:	chr = XK_Udiaeresis;	break;
423			case 0x60:	chr = XK_eacute;	break;
424			case 0x7b:	chr = XK_adiaeresis;	break;
425			case 0x7c:	chr = XK_odiaeresis;	break;
426			case 0x7d:	chr = XK_aring;		break;
427			case 0x7e:	chr = XK_udiaeresis;	break;
428			}
429			break;
430
431		case '=':	/* Swiss */
432			switch (chr = seven) {
433			case 0x23:	chr = XK_ugrave;	break;
434			case 0x40:	chr = XK_agrave;	break;
435			case 0x5b:	chr = XK_eacute;	break;
436			case 0x5c:	chr = XK_ccedilla;	break;
437			case 0x5d:	chr = XK_ecircumflex;	break;
438			case 0x5e:	chr = XK_icircumflex;	break;
439			case 0x5f:	chr = XK_egrave;	break;
440			case 0x60:	chr = XK_ocircumflex;	break;
441			case 0x7b:	chr = XK_adiaeresis;	break;
442			case 0x7c:	chr = XK_odiaeresis;	break;
443			case 0x7d:	chr = XK_udiaeresis;	break;
444			case 0x7e:	chr = XK_ucircumflex;	break;
445			}
446			break;
447
448		default:	/* any character sets we don't recognize*/
449			count --;
450			break;
451		}
452		/*
453		 * The state machine already treated DEL as a nonprinting and
454		 * nonspacing character.  If we have DEL now, simply render
455		 * it as a blank.
456		 */
457		if (chr == ANSI_DEL)
458		    chr = ' ';
459		*s = A2E(chr);
460	}
461	return count;
462}
463