summaryrefslogtreecommitdiff
path: root/charsets.c
diff options
context:
space:
mode:
Diffstat (limited to 'charsets.c')
-rw-r--r--charsets.c485
1 files changed, 485 insertions, 0 deletions
diff --git a/charsets.c b/charsets.c
new file mode 100644
index 0000000..45bea73
--- /dev/null
+++ b/charsets.c
@@ -0,0 +1,485 @@
+/* $XTermId: charsets.c,v 1.42 2011/09/11 14:40:17 tom Exp $ */
+
+/*
+ * Copyright 1998-2009,2011 by Thomas E. Dickey
+ *
+ * All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name(s) of the above copyright
+ * holders shall not be used in advertising or otherwise to promote the
+ * sale, use or other dealings in this Software without prior written
+ * authorization.
+ *
+ */
+
+#include <xterm.h>
+#include <data.h>
+#include <fontutils.h>
+
+#include <X11/keysym.h>
+
+/*
+ * This module performs translation as needed to support the DEC VT220 national
+ * replacement character sets. We assume that xterm's font is based on the ISO
+ * 8859-1 (Latin 1) character set, which is almost the same as the DEC
+ * multinational character set. Glyph positions 0-31 have to be the DEC
+ * graphic characters, though.
+ *
+ * References:
+ * "VT220 Programmer Pocket Guide" EK-VT220-HR-002 (2nd ed., 1984), which
+ * contains character charts for the national character sets.
+ * "VT330/VT340 Programmer Reference Manual Volume 1: Text Programming"
+ * EK-VT3XX-TP-001 (1st ed, 1987), which contains a table (2-1)
+ * listing the glyphs which are mapped from the multinational
+ * character set to the national character set.
+ *
+ * The latter reference, though easier to read, has a few errors and omissions.
+ */
+
+/*
+ * Translate an input keysym to the corresponding NRC keysym.
+ */
+unsigned
+xtermCharSetIn(unsigned code, int charset)
+{
+#define MAP(to, from) case from: code = to; break
+
+ if (code >= 128 && code < 256) {
+ switch (charset) {
+ case 'A': /* United Kingdom set (or Latin 1) */
+ if (code == XK_sterling)
+ code = 0x23;
+ code &= 0x7f;
+ break;
+
+#if OPT_XMC_GLITCH
+ case '?':
+#endif
+ case '1': /* Alternate Character ROM standard characters */
+ case '2': /* Alternate Character ROM special graphics */
+ case 'B': /* ASCII set */
+ break;
+
+ case '0': /* special graphics (line drawing) */
+ break;
+
+ case '4': /* Dutch */
+ switch (code) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_threequarters);
+ MAP(0x5b, XK_ydiaeresis);
+ MAP(0x5c, XK_onehalf);
+ MAP(0x5d, XK_bar); /* glyph is not ISO-8859-1 */
+ MAP(0x7b, XK_diaeresis);
+ MAP(0x7c, XK_f); /* glyph is not ISO-8859-1 */
+ MAP(0x7d, XK_onequarter);
+ MAP(0x7e, XK_acute);
+ }
+ break;
+
+ case 'C':
+ case '5': /* Finnish */
+ switch (code) {
+ MAP(0x5b, XK_Adiaeresis);
+ MAP(0x5c, XK_Odiaeresis);
+ MAP(0x5d, XK_Aring);
+ MAP(0x5e, XK_Udiaeresis);
+ MAP(0x60, XK_eacute);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_aring);
+ MAP(0x7e, XK_udiaeresis);
+ }
+ break;
+
+ case 'R': /* French */
+ switch (code) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_agrave);
+ MAP(0x5b, XK_degree);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_section);
+ MAP(0x7b, XK_eacute);
+ MAP(0x7c, XK_ugrave);
+ MAP(0x7d, XK_egrave);
+ MAP(0x7e, XK_diaeresis);
+ }
+ break;
+
+ case 'Q': /* French Canadian */
+ switch (code) {
+ MAP(0x40, XK_agrave);
+ MAP(0x5b, XK_acircumflex);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_ecircumflex);
+ MAP(0x5e, XK_icircumflex);
+ MAP(0x60, XK_ocircumflex);
+ MAP(0x7b, XK_eacute);
+ MAP(0x7c, XK_ugrave);
+ MAP(0x7d, XK_egrave);
+ MAP(0x7e, XK_ucircumflex);
+ }
+ break;
+
+ case 'K': /* German */
+ switch (code) {
+ MAP(0x40, XK_section);
+ MAP(0x5b, XK_Adiaeresis);
+ MAP(0x5c, XK_Odiaeresis);
+ MAP(0x5d, XK_Udiaeresis);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_udiaeresis);
+ MAP(0x7e, XK_ssharp);
+ }
+ break;
+
+ case 'Y': /* Italian */
+ switch (code) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_section);
+ MAP(0x5b, XK_degree);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_eacute);
+ MAP(0x60, XK_ugrave);
+ MAP(0x7b, XK_agrave);
+ MAP(0x7c, XK_ograve);
+ MAP(0x7d, XK_egrave);
+ MAP(0x7e, XK_igrave);
+ }
+ break;
+
+ case 'E':
+ case '6': /* Norwegian/Danish */
+ switch (code) {
+ MAP(0x40, XK_Adiaeresis);
+ MAP(0x5b, XK_AE);
+ MAP(0x5c, XK_Ooblique);
+ MAP(0x5d, XK_Aring);
+ MAP(0x5e, XK_Udiaeresis);
+ MAP(0x60, XK_adiaeresis);
+ MAP(0x7b, XK_ae);
+ MAP(0x7c, XK_oslash);
+ MAP(0x7d, XK_aring);
+ MAP(0x7e, XK_udiaeresis);
+ }
+ break;
+
+ case 'Z': /* Spanish */
+ switch (code) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_section);
+ MAP(0x5b, XK_exclamdown);
+ MAP(0x5c, XK_Ntilde);
+ MAP(0x5d, XK_questiondown);
+ MAP(0x7b, XK_degree);
+ MAP(0x7c, XK_ntilde);
+ MAP(0x7d, XK_ccedilla);
+ }
+ break;
+
+ case 'H':
+ case '7': /* Swedish */
+ switch (code) {
+ MAP(0x40, XK_Eacute);
+ MAP(0x5b, XK_Adiaeresis);
+ MAP(0x5c, XK_Odiaeresis);
+ MAP(0x5d, XK_Aring);
+ MAP(0x5e, XK_Udiaeresis);
+ MAP(0x60, XK_eacute);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_aring);
+ MAP(0x7e, XK_udiaeresis);
+ }
+ break;
+
+ case '=': /* Swiss */
+ switch (code) {
+ MAP(0x23, XK_ugrave);
+ MAP(0x40, XK_agrave);
+ MAP(0x5b, XK_eacute);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_ecircumflex);
+ MAP(0x5e, XK_icircumflex);
+ MAP(0x5f, XK_egrave);
+ MAP(0x60, XK_ocircumflex);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_udiaeresis);
+ MAP(0x7e, XK_ucircumflex);
+ }
+ break;
+
+ default: /* any character sets we don't recognize */
+ break;
+ }
+ code &= 0x7f; /* NRC in any case is 7-bit */
+ }
+ return code;
+#undef MAP
+}
+
+/*
+ * Translate a string to the display form. This assumes the font has the
+ * DEC graphic characters in cells 0-31, and otherwise is ISO-8859-1.
+ */
+int
+xtermCharSetOut(XtermWidget xw, IChar * buf, IChar * ptr, int leftset)
+{
+ IChar *s;
+ TScreen *screen = TScreenOf(xw);
+ int count = 0;
+ int rightset = screen->gsets[(int) (screen->curgr)];
+
+#define MAP(from, to) case from: chr = to; break
+
+ TRACE(("CHARSET GL=%c(G%d) GR=%c(G%d) SS%d\n\t%s\n",
+ leftset, screen->curgl,
+ rightset, screen->curgr,
+ screen->curss,
+ visibleIChar(buf, (unsigned) (ptr - buf))));
+
+ for (s = buf; s < ptr; ++s) {
+ int eight = CharOf(E2A(*s));
+ int seven = eight & 0x7f;
+ int cs = (eight >= 128) ? rightset : leftset;
+ int chr = eight;
+
+ count++;
+#if OPT_WIDE_CHARS
+ /*
+ * This is only partly right - prevent inadvertant remapping of
+ * the replacement character and other non-8bit codes into bogus
+ * 8bit codes.
+ */
+ if (screen->utf8_mode) {
+ if (*s > 255)
+ continue;
+ }
+#endif
+ switch (cs) {
+ case 'A': /* United Kingdom set (or Latin 1) */
+ if ((xw->flags & NATIONAL)
+ || (screen->vtXX_level <= 1)) {
+ if (chr == 0x23) {
+#if OPT_WIDE_CHARS
+ chr = (screen->utf8_mode
+ ? 0xa3
+ : XTERM_POUND);
+#else
+ chr = XTERM_POUND;
+#endif
+ }
+ } else {
+ chr = (seven | 0x80);
+ }
+ break;
+
+#if OPT_XMC_GLITCH
+ case '?':
+#endif
+ case '1': /* Alternate Character ROM standard characters */
+ case '2': /* Alternate Character ROM special graphics */
+ case 'B': /* ASCII set */
+ break;
+
+ case '0': /* special graphics (line drawing) */
+ if (seven > 0x5f && seven <= 0x7e) {
+#if OPT_WIDE_CHARS
+ if (screen->utf8_mode)
+ chr = (int) dec2ucs((unsigned) (seven - 0x5f));
+ else
+#endif
+ chr = seven - 0x5f;
+ } else {
+ chr = seven;
+ }
+ break;
+
+ case '4': /* Dutch */
+ switch (chr = seven) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_threequarters);
+ MAP(0x5b, XK_ydiaeresis);
+ MAP(0x5c, XK_onehalf);
+ MAP(0x5d, XK_bar);
+ MAP(0x7b, XK_diaeresis);
+ MAP(0x7c, XK_f);
+ MAP(0x7d, XK_onequarter);
+ MAP(0x7e, XK_acute);
+ }
+ break;
+
+ case 'C':
+ case '5': /* Finnish */
+ switch (chr = seven) {
+ MAP(0x5b, XK_Adiaeresis);
+ MAP(0x5c, XK_Odiaeresis);
+ MAP(0x5d, XK_Aring);
+ MAP(0x5e, XK_Udiaeresis);
+ MAP(0x60, XK_eacute);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_aring);
+ MAP(0x7e, XK_udiaeresis);
+ }
+ break;
+
+ case 'R': /* French */
+ switch (chr = seven) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_agrave);
+ MAP(0x5b, XK_degree);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_section);
+ MAP(0x7b, XK_eacute);
+ MAP(0x7c, XK_ugrave);
+ MAP(0x7d, XK_egrave);
+ MAP(0x7e, XK_diaeresis);
+ }
+ break;
+
+ case 'Q': /* French Canadian */
+ switch (chr = seven) {
+ MAP(0x40, XK_agrave);
+ MAP(0x5b, XK_acircumflex);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_ecircumflex);
+ MAP(0x5e, XK_icircumflex);
+ MAP(0x60, XK_ocircumflex);
+ MAP(0x7b, XK_eacute);
+ MAP(0x7c, XK_ugrave);
+ MAP(0x7d, XK_egrave);
+ MAP(0x7e, XK_ucircumflex);
+ }
+ break;
+
+ case 'K': /* German */
+ switch (chr = seven) {
+ MAP(0x40, XK_section);
+ MAP(0x5b, XK_Adiaeresis);
+ MAP(0x5c, XK_Odiaeresis);
+ MAP(0x5d, XK_Udiaeresis);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_udiaeresis);
+ MAP(0x7e, XK_ssharp);
+ }
+ break;
+
+ case 'Y': /* Italian */
+ switch (chr = seven) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_section);
+ MAP(0x5b, XK_degree);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_eacute);
+ MAP(0x60, XK_ugrave);
+ MAP(0x7b, XK_agrave);
+ MAP(0x7c, XK_ograve);
+ MAP(0x7d, XK_egrave);
+ MAP(0x7e, XK_igrave);
+ }
+ break;
+
+ case 'E':
+ case '6': /* Norwegian/Danish */
+ switch (chr = seven) {
+ MAP(0x40, XK_Adiaeresis);
+ MAP(0x5b, XK_AE);
+ MAP(0x5c, XK_Ooblique);
+ MAP(0x5d, XK_Aring);
+ MAP(0x5e, XK_Udiaeresis);
+ MAP(0x60, XK_adiaeresis);
+ MAP(0x7b, XK_ae);
+ MAP(0x7c, XK_oslash);
+ MAP(0x7d, XK_aring);
+ MAP(0x7e, XK_udiaeresis);
+ }
+ break;
+
+ case 'Z': /* Spanish */
+ switch (chr = seven) {
+ MAP(0x23, XK_sterling);
+ MAP(0x40, XK_section);
+ MAP(0x5b, XK_exclamdown);
+ MAP(0x5c, XK_Ntilde);
+ MAP(0x5d, XK_questiondown);
+ MAP(0x7b, XK_degree);
+ MAP(0x7c, XK_ntilde);
+ MAP(0x7d, XK_ccedilla);
+ }
+ break;
+
+ case 'H':
+ case '7': /* Swedish */
+ switch (chr = seven) {
+ MAP(0x40, XK_Eacute);
+ MAP(0x5b, XK_Adiaeresis);
+ MAP(0x5c, XK_Odiaeresis);
+ MAP(0x5d, XK_Aring);
+ MAP(0x5e, XK_Udiaeresis);
+ MAP(0x60, XK_eacute);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_aring);
+ MAP(0x7e, XK_udiaeresis);
+ }
+ break;
+
+ case '=': /* Swiss */
+ switch (chr = seven) {
+ MAP(0x23, XK_ugrave);
+ MAP(0x40, XK_agrave);
+ MAP(0x5b, XK_eacute);
+ MAP(0x5c, XK_ccedilla);
+ MAP(0x5d, XK_ecircumflex);
+ MAP(0x5e, XK_icircumflex);
+ MAP(0x5f, XK_egrave);
+ MAP(0x60, XK_ocircumflex);
+ MAP(0x7b, XK_adiaeresis);
+ MAP(0x7c, XK_odiaeresis);
+ MAP(0x7d, XK_udiaeresis);
+ MAP(0x7e, XK_ucircumflex);
+ }
+ break;
+
+ default: /* any character sets we don't recognize */
+ count--;
+ break;
+ }
+ /*
+ * The state machine already treated DEL as a nonprinting and
+ * nonspacing character. If we have DEL now, simply render
+ * it as a blank.
+ */
+ if (chr == ANSI_DEL)
+ chr = ' ';
+ *s = (IChar) A2E(chr);
+ }
+ TRACE(("%d\t%s\n",
+ count,
+ visibleIChar(buf, (unsigned) (ptr - buf))));
+ return count;
+#undef MAP
+}