Implement a Makefile for Inform.
[inform.git] / src / chars.c
diff --git a/src/chars.c b/src/chars.c
new file mode 100644 (file)
index 0000000..e91e9c1
--- /dev/null
@@ -0,0 +1,1324 @@
+/* ------------------------------------------------------------------------- */
+/*   "chars" : Character set mappings and the Z-machine alphabet table       */
+/*                                                                           */
+/* Copyright (c) Graham Nelson 1993 - 2018                                   */
+/*                                                                           */
+/* This file is part of Inform.                                              */
+/*                                                                           */
+/* Inform is free software: you can redistribute it and/or modify            */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation, either version 3 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* Inform is distributed in the hope that it will be useful,                 */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with Inform. If not, see https://gnu.org/licenses/                  */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+/*  Inform uses six different character representations:                     */
+/*                                                                           */
+/*      ASCII      plain ASCII characters in range $20 to $7e                */
+/*                     (unsigned 7-bit number)                               */
+/*      Source     raw bytes from source code                                */
+/*                     (unsigned 8-bit number)                               */
+/*      ISO        plain ASCII or ISO 8859-1 to -9, according to value       */
+/*                     character_set_setting == 0 or 1 to 9                  */
+/*                 in Unicode mode (character_set_unicode), individual       */
+/*                     UTF-8 bytes                                           */
+/*                     (unsigned 8-bit number)                               */
+/*      ZSCII      the Z-machine's character set                             */
+/*                     (unsigned 10-bit number)                              */
+/*      textual    such as the text @'e to mean e-acute                      */
+/*                     or @$03a3 to mean capital Greek sigma                 */
+/*                 in Unicode mode, the operations manipulating multibyte    */
+/*                     UCS representations are included in text routines     */
+/*                     (sequence of ASCII characters)                        */
+/*      Unicode    a unifying character set holding all possible characters  */
+/*                     Inform can ever deal with                             */
+/*                     (unsigned 16-bit number)                              */
+/*                                                                           */
+/*  Conversion can always be made down this list, but generally not up.      */
+/*  Note that all ASCII values are the same in any version of ISO            */
+/*  and in Unicode.                                                          */
+/*                                                                           */
+/*  There is a seventh form: sequences of 5-bit "Z-chars" which encode       */
+/*  ZSCII into the story file in compressed form.  Conversion of ZSCII to    */
+/*  and from Z-char sequences, although it uses the alphabet table, is done  */
+/*  in "text.c".                                                             */
+/* ------------------------------------------------------------------------- */
+/*  The main data structures need to be modified in mid-compilation, but     */
+/*  several of them depend on each other, and must remain consistent;        */
+/*  and rebuilding one sometimes uses conversion routines depending on       */
+/*  information held in the others:                                          */
+/*                                                                           */
+/*      Structure                   If changed, need to rebuild:             */
+/*      character_set_setting       source_to_iso_grid[]                     */
+/*                                  zscii_to_unicode_grid[]                  */
+/*                                  zscii_to_iso_grid[]                      */
+/*                                  iso_to_unicode_grid[]                    */
+/*      alphabet[][]                iso_to_alphabet_grid[]                   */
+/*                                  zscii_to_alphabet_grid[]                 */
+/*      zscii_to_unicode_grid[]     iso_to_alphabet_grid[]                   */
+/*      source_to_iso_grid[]        <nothing>                                */
+/*      iso_to_alphabet_grid[]      <nothing>                                */
+/*      zscii_to_alphabet_grid[]    <nothing>                                */
+/*      zscii_to_iso_grid[]         <nothing>                                */
+/*                                                                           */
+/*      (zscii_to_iso_grid[] is made whenever iso_to_alphabet_grid[] is      */
+/*      made but does not depend on alphabet[].)                             */
+/*                                                                           */
+/*      Conversion routine          Makes use of:                            */
+/*      iso_to_unicode              character_set_setting                    */
+/*      unicode_to_zscii            character_set_setting                    */
+/*                                  zscii_to_unicode_grid[]                  */
+/*      zscii_to_unicode            character_set_setting                    */
+/*                                  zscii_to_unicode_grid[]                  */
+/*      text_to_unicode             <nothing>                                */
+/*      zscii_to_text               character_set_setting                    */
+/*                                  zscii_to_unicode_grid[]                  */
+/*                                  zscii_to_iso_grid[]                      */
+/*                                                                           */
+/*  For example, if we want to change alphabet[][] then we can safely        */
+/*  use any of the conversion routines while working on the change, but      */
+/*  must rebuild the iso_to_alphabet_grid[] before allowing Inform to        */
+/*  continue compiling.                                                      */
+/* ------------------------------------------------------------------------- */
+
+#include "header.h"
+
+uchar source_to_iso_grid[0x100];       /* Filters source code into legal ISO */
+
+int32 iso_to_unicode_grid[0x100];      /* Filters ISO into Unicode           */
+
+int character_digit_value[128];        /* Parsing of binary, decimal and hex */
+
+static char *accents =                 /* Standard 0.2 stock of accented...  */
+
+   ":a:o:u:A:O:Uss>><<:e:i:y:E:I'a'e'i'o'u'y'A'E'I'O'U'Y`a`e`i`o`u\
+`A`E`I`O`U^a^e^i^o^u^A^E^I^O^UoaoA/o/O~a~n~o~A~N~OaeAEcccCthetThEtLLoeOE!!??";
+
+                                       /* ...characters, numbered upwards    */
+                                       /* from 155                           */
+
+/* ------------------------------------------------------------------------- */
+
+uchar alphabet[3][27];                  /* The alphabet table. */
+
+int alphabet_modified;                 /* Has the default been changed?      */
+
+char alphabet_used[78];                /* Flags (holding 'N' or 'Y') for
+                                          which of the Z-alphabet letters
+                                          have actually been encrypted       */
+
+/* ------------------------------------------------------------------------- */
+
+int iso_to_alphabet_grid[0x100];
+
+/* This array combines two conversion processes which have to run quickly:
+   an ISO character n is being converted for text purposes into a stream
+   of Z-chars (anything from 1 up to 8 of these).  Unicode but non-ISO
+   characters are also converted from text, but far less often, and
+   different (and slower) methods are used to carry this out.
+
+   iso_to_alphabet_grid[n]
+       =  i   if the character exists in ZSCII and is located at
+              position i in the Z-machine alphabet (where 0 to 25
+              give positions in A0, 26 to 51 in A1 and 52 to 77 in A2);
+
+          -z  if the character exists in ZSCII as value z, but is not
+              located anywhere in the Z-machine alphabet;
+
+          -5  if the character does not exist in ZSCII.  (It will still
+              be printable using an 8-Z-char sequence to encode it in
+              Unicode form, but there's no ZSCII form.)
+
+   Note that ISO tilde ~ is interpreted as ZSCII double-quote ",
+   and ISO circumflex ^ is interpreted as ZSCII new-line, in accordance
+   with the Inform syntax for strings.  This is automatic from the
+   structure of alphabet[][]:
+
+   alphabet[i][j] = the ZSCII code of letter j (0 to 25)
+                        in alphabet i (0 to 2)
+
+                    _except that_
+
+                    alphabet[2][0] is ignored by the Z-machine and Inform
+                                   (char 0 in A2 is an escape)
+                    alphabet[2][1] is ignored by the Z-machine
+                                   (char 1 in A2 means new-line)
+                                   but used by Inform to hold ISO circumflex
+                                   so that ^ is translated as new-line
+                    alphabet[2][19] is used by Inform to hold ISO tilde
+                                   so that ~ is translated as ": after
+                                   compilation, when the alphabet table is
+                                   written into the Z-machine, this entry
+                                   is changed back to ".
+
+   Note that the alphabet can only hold ZSCII values between 0 and 255.
+
+   The array is dimensioned as [3][27], not [3][26], to make it easier to
+   initialise using strcpy (see below), but the zero entries [x][26] are
+   not used                                                                 */
+
+int zscii_to_alphabet_grid[0x100];
+
+/* The same, except that the index is a ZSCII character, not an ISO one.    */
+
+int zscii_to_iso_grid[0x100];      /* Converts ZSCII between 0 and 255 to
+                                      codes in current ISO set: or to 0 if
+                                      code isn't in the current ISO set.    */
+
+static void make_iso_to_alphabet_grid(void)
+{   int i, j, k; int z;
+
+    for (j=0; j<0x100; j++)
+    {   zscii_to_iso_grid[j] = 0;
+        zscii_to_alphabet_grid[j] = -j;
+    }
+
+    for (j=0; j<0x100; j++)
+    {   iso_to_alphabet_grid[j]=-5;
+        if ((j >= 0x20) && (j <= 0x7e))
+        {   iso_to_alphabet_grid[j] = -j;
+            zscii_to_iso_grid[j] = j;
+        }
+        if ((j >= 0xa1) && (j <= 0xff))
+        {   z = unicode_to_zscii(iso_to_unicode(j));
+            if (character_set_setting != 0)
+                zscii_to_iso_grid[z] = j;
+            iso_to_alphabet_grid[j] = -z;
+        }
+        iso_to_unicode_grid[j] = iso_to_unicode(j);
+    }
+    for (j=0; j<3; j++)
+        for (k=(j<2?0:1); k<26; k++)
+            {   i=(int) ((alphabet[j])[k]);
+                zscii_to_alphabet_grid[i] = k + j*26;
+                iso_to_alphabet_grid[zscii_to_iso_grid[i]] = k + j*26;
+            }
+}
+
+extern void map_new_zchar(int32 unicode)
+{   /*  Attempts to enter the given Unicode character into the "alphabet[]"
+        array, in place of one which has not so far been used in the
+        compilation of the current file.  This may of course fail.           */
+
+    int i, j; int zscii;
+
+    zscii = unicode_to_zscii(unicode);
+
+    /*  Out of ZSCII range?  */
+    if ((zscii == 5) || (zscii >= 0x100))
+    {   unicode_char_error(
+            "Character must first be entered into Zcharacter table:", unicode);
+        return;
+    }
+
+    /*  Already there?  */
+    for (i=0;i<3;i++) for (j=0;j<26;j++)
+        if (alphabet[i][j] == zscii) return;
+
+    /*  A0 and A1 are never changed.  Try to find a place in alphabet A2:
+
+        xx0123456789.,!?_#'~/\-:()
+          ^^^^^^^^^^  ^^^^^ ^^^^^^
+
+        The letters marked ^ are considered to be replaceable, as long as
+        they haven't yet been used in any text already encoded, and haven't
+        already been replaced.  The routine works along from the left, since
+        numerals are more of a luxury than punctuation.                      */
+
+    for (i=2; i<26; i++)
+    {   if ((i == 12) || (i == 13) || (i == 19)) continue;
+        if (alphabet_used[52+i] == 'N')
+        {   alphabet_used[52+i] = 'Y';
+            alphabet[2][i] = zscii;
+            alphabet_modified = TRUE;
+            make_iso_to_alphabet_grid();
+            return;
+        }
+    }
+}
+
+extern void new_alphabet(char *text, int which_alph)
+{
+    /*  Called three times in succession, with which_alph = 0, 1, 2  */
+
+    int i, j, zscii; int32 unicode;
+
+    alphabet_modified = TRUE;
+
+    if (which_alph == 2)
+    {   i=3; alphabet[2][2] = '~';
+    }
+    else i=0;
+
+    for (j=0; i<26; i++)
+    {   if (text[j] == 0) goto WrongSizeError;
+
+        unicode = text_to_unicode(text+j);
+        j += textual_form_length;
+
+        zscii = unicode_to_zscii(unicode);
+        if ((zscii == 5) || (zscii >= 0x100))
+            unicode_char_error("Character can't be used in alphabets unless \
+entered into Zcharacter table", unicode);
+        else alphabet[which_alph][i] = zscii;
+    }
+
+    if (text[j] != 0)
+    {   WrongSizeError:
+        if (which_alph == 2)
+            error("Alphabet string must give exactly 23 characters");
+        else
+            error("Alphabet string must give exactly 26 characters");
+    }
+
+    if (which_alph == 2)
+    {   int test_dups[0x100];
+        for (i=0; i<0x100; i++) test_dups[i] = 0;
+        for (i=0; i<3; i++) for (j=0; j<26; j++)
+        {   if (test_dups[alphabet[i][j]]++ == 1)
+                unicode_char_error("Character duplicated in alphabet:",
+                    zscii_to_unicode(alphabet[i][j]));
+        }
+
+        make_iso_to_alphabet_grid();
+    }
+}
+
+static void read_source_to_iso_file(uchar *uccg)
+{   FILE *charset_file;
+    char cs_buff[256];
+    char *p;
+    int i=0;
+
+    charset_file=fopen(Charset_Map, "r");
+    if (charset_file==NULL)
+        fatalerror_named("Couldn't open character set mapping", Charset_Map);
+
+    while (feof(charset_file)==0)
+    {   if (fgets(cs_buff,256,charset_file)==0) break;
+
+        switch (cs_buff[0])
+        {   case '!': /* Ignore comments in file */
+                break;
+            case 'C': /* Set character set */
+                character_set_setting = cs_buff[1]-'0';
+                if ((character_set_setting < 0) || (character_set_setting > 9))
+                {   fatalerror_named("Character set in mapping must be 0 to 9",
+                        Charset_Map);
+                }
+                break;
+            default:
+                p = cs_buff;
+                while ((i<256) && (p!=NULL))
+                {
+                    uccg[i++] = (uchar)atoi(p);
+                    p = strchr(p,',');
+                    if (p != NULL)
+                        p++;
+                }
+                break;
+        }
+    }
+    fclose(charset_file);
+}
+
+/* ========================================================================= */
+/*   Conversion functions (without side effects)                             */
+/* ------------------------------------------------------------------------- */
+/*  (1) Source -> ISO                                                        */
+/*                                                                           */
+/*      00         remains 0 (meaning "end of file")                         */
+/*      TAB        becomes SPACE                                             */
+/*      0c         ("form feed") becomes '\n'                                */
+/*      0d         becomes '\n'                                              */
+/*      other control characters become '?'                                  */
+/*      7f         becomes '?'                                               */
+/*      80 to 9f   become '?'                                                */
+/*      a0         (ISO "non-breaking space") becomes SPACE                  */
+/*      ad         (ISO "soft hyphen") becomes '-'                           */
+/*      any character undefined in ISO is mapped to '?'                      */
+/*      In Unicode mode, characters 80 and upwards are preserved.            */
+/*                                                                           */
+/* ------------------------------------------------------------------------- */
+
+static void make_source_to_iso_grid(void)
+{   int n; uchar *uccg = (uchar *) source_to_iso_grid;
+
+    for (n=0; n<0x100; n++) uccg[n] = (char) n;
+
+    if (Charset_Map[0] != '\0')
+        read_source_to_iso_file(uccg);
+    else
+    {   source_to_iso_grid[0] = (char) 0;
+        for (n=1; n<32; n++) source_to_iso_grid[n] = '?';
+        source_to_iso_grid[10] = '\n';
+        source_to_iso_grid[12] = '\n';
+        source_to_iso_grid[13] = '\n';
+        source_to_iso_grid[127] = '?';
+        source_to_iso_grid[TAB_CHARACTER] = ' ';
+
+        if (character_set_unicode) /* No need to meddle with 8-bit for UTF-8 */
+            return;
+
+        for (n=0x80; n<0xa0; n++) source_to_iso_grid[n] = '?';
+        source_to_iso_grid[0xa0] = ' ';
+        source_to_iso_grid[0xad] = '-';
+
+        switch(character_set_setting)
+        {   case 0:
+                for (n=0xa0; n<0x100; n++)
+                     source_to_iso_grid[n] = '?';
+                break;
+            case 6:  /* Arabic */
+                for (n=0xa0; n<0xc1; n++)
+                    switch(n)
+                    {   case 0xa0: case 0xa4: case 0xac: case 0xad:
+                        case 0xbb: case 0xbf: break;
+                        default: source_to_iso_grid[n] = '?';
+                    }
+                for (n=0xdb; n<0xe0; n++)
+                     source_to_iso_grid[n] = '?';
+                for (n=0xf3; n<0x100; n++)
+                     source_to_iso_grid[n] = '?';
+                break;
+            case 7:  /* Greek */
+                source_to_iso_grid[0xa4] = '?';
+                source_to_iso_grid[0xa5] = '?';
+                source_to_iso_grid[0xaa] = '?';
+                source_to_iso_grid[0xae] = '?';
+                source_to_iso_grid[0xd2] = '?';
+                source_to_iso_grid[0xff] = '?';
+                break;
+            case 8:  /* Hebrew */
+                source_to_iso_grid[0xa1] = '?';
+                for (n=0xbf; n<0xdf; n++)
+                     source_to_iso_grid[n] = '?';
+                for (n=0xfb; n<0x100; n++)
+                     source_to_iso_grid[n] = '?';
+                break;
+        }
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+/*  (2) ISO -> Unicode                                                       */
+/*                                                                           */
+/*     Need not be rapid, as the results are mostly cached.                  */
+/*     Always succeeds.                                                      */
+/* ------------------------------------------------------------------------- */
+
+extern int iso_to_unicode(int iso)
+{   int u = iso;
+    switch(character_set_setting)
+    {
+
+  case 0: /* Plain ASCII only */
+  break;
+
+  case 1: /* ISO 8859-1: Latin1: west European */
+  break;
+
+  case 2: /* ISO 8859-2: Latin2: central European */
+
+switch(iso)
+{ case 0xA1: u=0x0104; break; /* LATIN CAP A WITH OGONEK */
+  case 0xA2: u=0x02D8; break; /* BREVE */
+  case 0xA3: u=0x0141; break; /* LATIN CAP L WITH STROKE */
+  case 0xA5: u=0x013D; break; /* LATIN CAP L WITH CARON */
+  case 0xA6: u=0x015A; break; /* LATIN CAP S WITH ACUTE */
+  case 0xA9: u=0x0160; break; /* LATIN CAP S WITH CARON */
+  case 0xAA: u=0x015E; break; /* LATIN CAP S WITH CEDILLA */
+  case 0xAB: u=0x0164; break; /* LATIN CAP T WITH CARON */
+  case 0xAC: u=0x0179; break; /* LATIN CAP Z WITH ACUTE */
+  case 0xAE: u=0x017D; break; /* LATIN CAP Z WITH CARON */
+  case 0xAF: u=0x017B; break; /* LATIN CAP Z WITH DOT ABOVE */
+  case 0xB1: u=0x0105; break; /* LATIN SMALL A WITH OGONEK */
+  case 0xB2: u=0x02DB; break; /* OGONEK */
+  case 0xB3: u=0x0142; break; /* LATIN SMALL L WITH STROKE */
+  case 0xB5: u=0x013E; break; /* LATIN SMALL L WITH CARON */
+  case 0xB6: u=0x015B; break; /* LATIN SMALL S WITH ACUTE */
+  case 0xB7: u=0x02C7; break; /* CARON */
+  case 0xB9: u=0x0161; break; /* LATIN SMALL S WITH CARON */
+  case 0xBA: u=0x015F; break; /* LATIN SMALL S WITH CEDILLA */
+  case 0xBB: u=0x0165; break; /* LATIN SMALL T WITH CARON */
+  case 0xBC: u=0x017A; break; /* LATIN SMALL Z WITH ACUTE */
+  case 0xBD: u=0x02DD; break; /* DOUBLE ACUTE ACCENT */
+  case 0xBE: u=0x017E; break; /* LATIN SMALL Z WITH CARON */
+  case 0xBF: u=0x017C; break; /* LATIN SMALL Z WITH DOT ABOVE */
+  case 0xC0: u=0x0154; break; /* LATIN CAP R WITH ACUTE */
+  case 0xC3: u=0x0102; break; /* LATIN CAP A WITH BREVE */
+  case 0xC5: u=0x0139; break; /* LATIN CAP L WITH ACUTE */
+  case 0xC6: u=0x0106; break; /* LATIN CAP C WITH ACUTE */
+  case 0xC8: u=0x010C; break; /* LATIN CAP C WITH CARON */
+  case 0xCA: u=0x0118; break; /* LATIN CAP E WITH OGONEK */
+  case 0xCC: u=0x011A; break; /* LATIN CAP E WITH CARON */
+  case 0xCF: u=0x010E; break; /* LATIN CAP D WITH CARON */
+  case 0xD0: u=0x0110; break; /* LATIN CAP D WITH STROKE */
+  case 0xD1: u=0x0143; break; /* LATIN CAP N WITH ACUTE */
+  case 0xD2: u=0x0147; break; /* LATIN CAP N WITH CARON */
+  case 0xD5: u=0x0150; break; /* LATIN CAP O WITH DOUBLE ACUTE */
+  case 0xD8: u=0x0158; break; /* LATIN CAP R WITH CARON */
+  case 0xD9: u=0x016E; break; /* LATIN CAP U WITH RING ABOVE */
+  case 0xDB: u=0x0170; break; /* LATIN CAP U WITH DOUBLE ACUTE */
+  case 0xDE: u=0x0162; break; /* LATIN CAP T WITH CEDILLA */
+  case 0xE0: u=0x0155; break; /* LATIN SMALL R WITH ACUTE */
+  case 0xE3: u=0x0103; break; /* LATIN SMALL A WITH BREVE */
+  case 0xE5: u=0x013A; break; /* LATIN SMALL L WITH ACUTE */
+  case 0xE6: u=0x0107; break; /* LATIN SMALL C WITH ACUTE */
+  case 0xE8: u=0x010D; break; /* LATIN SMALL C WITH CARON */
+  case 0xEA: u=0x0119; break; /* LATIN SMALL E WITH OGONEK */
+  case 0xEC: u=0x011B; break; /* LATIN SMALL E WITH CARON */
+  case 0xEF: u=0x010F; break; /* LATIN SMALL D WITH CARON */
+  case 0xF0: u=0x0111; break; /* LATIN SMALL D WITH STROKE */
+  case 0xF1: u=0x0144; break; /* LATIN SMALL N WITH ACUTE */
+  case 0xF2: u=0x0148; break; /* LATIN SMALL N WITH CARON */
+  case 0xF5: u=0x0151; break; /* LATIN SMALL O WITH DOUBLE ACUTE */
+  case 0xF8: u=0x0159; break; /* LATIN SMALL R WITH CARON */
+  case 0xF9: u=0x016F; break; /* LATIN SMALL U WITH RING ABOVE */
+  case 0xFB: u=0x0171; break; /* LATIN SMALL U WITH DOUBLE ACUTE */
+  case 0xFE: u=0x0163; break; /* LATIN SMALL T WITH CEDILLA */
+  case 0xFF: u=0x02D9; break; /* DOT ABOVE */
+} break;
+
+  case 3: /* ISO 8859-3: Latin3: central European */
+
+switch(iso)
+{ case 0xA1: u=0x0126; break; /* LATIN CAP H WITH STROKE */
+  case 0xA2: u=0x02D8; break; /* BREVE */
+  case 0xA6: u=0x0124; break; /* LATIN CAP H WITH CIRCUMFLEX */
+  case 0xA9: u=0x0130; break; /* LATIN CAP I WITH DOT ABOVE */
+  case 0xAA: u=0x015E; break; /* LATIN CAP S WITH CEDILLA */
+  case 0xAB: u=0x011E; break; /* LATIN CAP G WITH BREVE */
+  case 0xAC: u=0x0134; break; /* LATIN CAP J WITH CIRCUMFLEX */
+  case 0xAF: u=0x017B; break; /* LATIN CAP Z WITH DOT ABOVE */
+  case 0xB1: u=0x0127; break; /* LATIN SMALL H WITH STROKE */
+  case 0xB6: u=0x0125; break; /* LATIN SMALL H WITH CIRCUMFLEX */
+  case 0xB9: u=0x0131; break; /* LATIN SMALL DOTLESS I */
+  case 0xBA: u=0x015F; break; /* LATIN SMALL S WITH CEDILLA */
+  case 0xBB: u=0x011F; break; /* LATIN SMALL G WITH BREVE */
+  case 0xBC: u=0x0135; break; /* LATIN SMALL J WITH CIRCUMFLEX */
+  case 0xBF: u=0x017C; break; /* LATIN SMALL Z WITH DOT ABOVE */
+  case 0xC5: u=0x010A; break; /* LATIN CAP C WITH DOT ABOVE */
+  case 0xC6: u=0x0108; break; /* LATIN CAP C WITH CIRCUMFLEX */
+  case 0xD5: u=0x0120; break; /* LATIN CAP G WITH DOT ABOVE */
+  case 0xD8: u=0x011C; break; /* LATIN CAP G WITH CIRCUMFLEX */
+  case 0xDD: u=0x016C; break; /* LATIN CAP U WITH BREVE */
+  case 0xDE: u=0x015C; break; /* LATIN CAP S WITH CIRCUMFLEX */
+  case 0xE5: u=0x010B; break; /* LATIN SMALL C WITH DOT ABOVE */
+  case 0xE6: u=0x0109; break; /* LATIN SMALL C WITH CIRCUMFLEX */
+  case 0xF5: u=0x0121; break; /* LATIN SMALL G WITH DOT ABOVE */
+  case 0xF8: u=0x011D; break; /* LATIN SMALL G WITH CIRCUMFLEX */
+  case 0xFD: u=0x016D; break; /* LATIN SMALL U WITH BREVE */
+  case 0xFE: u=0x015D; break; /* LATIN SMALL S WITH CIRCUMFLEX */
+  case 0xFF: u=0x02D9; break; /* DOT ABOVE */
+} break;
+
+  case 4: /* ISO 8859-4: Latin4: central European */
+
+switch(iso)
+{ case 0xA1: u=0x0104; break; /* LATIN CAP A WITH OGONEK */
+  case 0xA2: u=0x0138; break; /* LATIN SMALL KRA */
+  case 0xA3: u=0x0156; break; /* LATIN CAP R WITH CEDILLA */
+  case 0xA5: u=0x0128; break; /* LATIN CAP I WITH TILDE */
+  case 0xA6: u=0x013B; break; /* LATIN CAP L WITH CEDILLA */
+  case 0xA9: u=0x0160; break; /* LATIN CAP S WITH CARON */
+  case 0xAA: u=0x0112; break; /* LATIN CAP E WITH MACRON */
+  case 0xAB: u=0x0122; break; /* LATIN CAP G WITH CEDILLA */
+  case 0xAC: u=0x0166; break; /* LATIN CAP T WITH STROKE */
+  case 0xAE: u=0x017D; break; /* LATIN CAP Z WITH CARON */
+  case 0xB1: u=0x0105; break; /* LATIN SMALL A WITH OGONEK */
+  case 0xB2: u=0x02DB; break; /* OGONEK */
+  case 0xB3: u=0x0157; break; /* LATIN SMALL R WITH CEDILLA */
+  case 0xB5: u=0x0129; break; /* LATIN SMALL I WITH TILDE */
+  case 0xB6: u=0x013C; break; /* LATIN SMALL L WITH CEDILLA */
+  case 0xB7: u=0x02C7; break; /* CARON */
+  case 0xB9: u=0x0161; break; /* LATIN SMALL S WITH CARON */
+  case 0xBA: u=0x0113; break; /* LATIN SMALL E WITH MACRON */
+  case 0xBB: u=0x0123; break; /* LATIN SMALL G WITH CEDILLA */
+  case 0xBC: u=0x0167; break; /* LATIN SMALL T WITH STROKE */
+  case 0xBD: u=0x014A; break; /* LATIN CAP ENG */
+  case 0xBE: u=0x017E; break; /* LATIN SMALL Z WITH CARON */
+  case 0xBF: u=0x014B; break; /* LATIN SMALL ENG */
+  case 0xC0: u=0x0100; break; /* LATIN CAP A WITH MACRON */
+  case 0xC7: u=0x012E; break; /* LATIN CAP I WITH OGONEK */
+  case 0xC8: u=0x010C; break; /* LATIN CAP C WITH CARON */
+  case 0xCA: u=0x0118; break; /* LATIN CAP E WITH OGONEK */
+  case 0xCC: u=0x0116; break; /* LATIN CAP E WITH DOT ABOVE */
+  case 0xCF: u=0x012A; break; /* LATIN CAP I WITH MACRON */
+  case 0xD0: u=0x0110; break; /* LATIN CAP D WITH STROKE */
+  case 0xD1: u=0x0145; break; /* LATIN CAP N WITH CEDILLA */
+  case 0xD2: u=0x014C; break; /* LATIN CAP O WITH MACRON */
+  case 0xD3: u=0x0136; break; /* LATIN CAP K WITH CEDILLA */
+  case 0xD9: u=0x0172; break; /* LATIN CAP U WITH OGONEK */
+  case 0xDD: u=0x0168; break; /* LATIN CAP U WITH TILDE */
+  case 0xDE: u=0x016A; break; /* LATIN CAP U WITH MACRON */
+  case 0xE0: u=0x0101; break; /* LATIN SMALL A WITH MACRON */
+  case 0xE7: u=0x012F; break; /* LATIN SMALL I WITH OGONEK */
+  case 0xE8: u=0x010D; break; /* LATIN SMALL C WITH CARON */
+  case 0xEA: u=0x0119; break; /* LATIN SMALL E WITH OGONEK */
+  case 0xEC: u=0x0117; break; /* LATIN SMALL E WITH DOT ABOVE */
+  case 0xEF: u=0x012B; break; /* LATIN SMALL I WITH MACRON */
+  case 0xF0: u=0x0111; break; /* LATIN SMALL D WITH STROKE */
+  case 0xF1: u=0x0146; break; /* LATIN SMALL N WITH CEDILLA */
+  case 0xF2: u=0x014D; break; /* LATIN SMALL O WITH MACRON */
+  case 0xF3: u=0x0137; break; /* LATIN SMALL K WITH CEDILLA */
+  case 0xF9: u=0x0173; break; /* LATIN SMALL U WITH OGONEK */
+  case 0xFD: u=0x0169; break; /* LATIN SMALL U WITH TILDE */
+  case 0xFE: u=0x016B; break; /* LATIN SMALL U WITH MACRON */
+  case 0xFF: u=0x02D9; break; /* DOT ABOVE */
+} break;
+
+  case 5: /* ISO 8859-5: Cyrillic */
+
+switch(iso)
+{ case 0xA1: u=0x0401; break; /* CYRILLIC CAP IO */
+  case 0xA2: u=0x0402; break; /* CYRILLIC CAP DJE */
+  case 0xA3: u=0x0403; break; /* CYRILLIC CAP GJE */
+  case 0xA4: u=0x0404; break; /* CYRILLIC CAP UKRAINIAN IE */
+  case 0xA5: u=0x0405; break; /* CYRILLIC CAP DZE */
+  case 0xA6: u=0x0406; break; /* CYRILLIC CAP BYELORUSSIAN-UKRAINIAN I */
+  case 0xA7: u=0x0407; break; /* CYRILLIC CAP YI */
+  case 0xA8: u=0x0408; break; /* CYRILLIC CAP JE */
+  case 0xA9: u=0x0409; break; /* CYRILLIC CAP LJE */
+  case 0xAA: u=0x040A; break; /* CYRILLIC CAP NJE */
+  case 0xAB: u=0x040B; break; /* CYRILLIC CAP TSHE */
+  case 0xAC: u=0x040C; break; /* CYRILLIC CAP KJE */
+  case 0xAE: u=0x040E; break; /* CYRILLIC CAP SHORT U */
+  case 0xAF: u=0x040F; break; /* CYRILLIC CAP DZHE */
+  case 0xB0: u=0x0410; break; /* CYRILLIC CAP A */
+  case 0xB1: u=0x0411; break; /* CYRILLIC CAP BE */
+  case 0xB2: u=0x0412; break; /* CYRILLIC CAP VE */
+  case 0xB3: u=0x0413; break; /* CYRILLIC CAP GHE */
+  case 0xB4: u=0x0414; break; /* CYRILLIC CAP DE */
+  case 0xB5: u=0x0415; break; /* CYRILLIC CAP IE */
+  case 0xB6: u=0x0416; break; /* CYRILLIC CAP ZHE */
+  case 0xB7: u=0x0417; break; /* CYRILLIC CAP ZE */
+  case 0xB8: u=0x0418; break; /* CYRILLIC CAP I */
+  case 0xB9: u=0x0419; break; /* CYRILLIC CAP SHORT I */
+  case 0xBA: u=0x041A; break; /* CYRILLIC CAP KA */
+  case 0xBB: u=0x041B; break; /* CYRILLIC CAP EL */
+  case 0xBC: u=0x041C; break; /* CYRILLIC CAP EM */
+  case 0xBD: u=0x041D; break; /* CYRILLIC CAP EN */
+  case 0xBE: u=0x041E; break; /* CYRILLIC CAP O */
+  case 0xBF: u=0x041F; break; /* CYRILLIC CAP PE */
+  case 0xC0: u=0x0420; break; /* CYRILLIC CAP ER */
+  case 0xC1: u=0x0421; break; /* CYRILLIC CAP ES */
+  case 0xC2: u=0x0422; break; /* CYRILLIC CAP TE */
+  case 0xC3: u=0x0423; break; /* CYRILLIC CAP U */
+  case 0xC4: u=0x0424; break; /* CYRILLIC CAP EF */
+  case 0xC5: u=0x0425; break; /* CYRILLIC CAP HA */
+  case 0xC6: u=0x0426; break; /* CYRILLIC CAP TSE */
+  case 0xC7: u=0x0427; break; /* CYRILLIC CAP CHE */
+  case 0xC8: u=0x0428; break; /* CYRILLIC CAP SHA */
+  case 0xC9: u=0x0429; break; /* CYRILLIC CAP SHCHA */
+  case 0xCA: u=0x042A; break; /* CYRILLIC CAP HARD SIGN */
+  case 0xCB: u=0x042B; break; /* CYRILLIC CAP YERU */
+  case 0xCC: u=0x042C; break; /* CYRILLIC CAP SOFT SIGN */
+  case 0xCD: u=0x042D; break; /* CYRILLIC CAP E */
+  case 0xCE: u=0x042E; break; /* CYRILLIC CAP YU */
+  case 0xCF: u=0x042F; break; /* CYRILLIC CAP YA */
+  case 0xD0: u=0x0430; break; /* CYRILLIC SMALL A */
+  case 0xD1: u=0x0431; break; /* CYRILLIC SMALL BE */
+  case 0xD2: u=0x0432; break; /* CYRILLIC SMALL VE */
+  case 0xD3: u=0x0433; break; /* CYRILLIC SMALL GHE */
+  case 0xD4: u=0x0434; break; /* CYRILLIC SMALL DE */
+  case 0xD5: u=0x0435; break; /* CYRILLIC SMALL IE */
+  case 0xD6: u=0x0436; break; /* CYRILLIC SMALL ZHE */
+  case 0xD7: u=0x0437; break; /* CYRILLIC SMALL ZE */
+  case 0xD8: u=0x0438; break; /* CYRILLIC SMALL I */
+  case 0xD9: u=0x0439; break; /* CYRILLIC SMALL SHORT I */
+  case 0xDA: u=0x043A; break; /* CYRILLIC SMALL KA */
+  case 0xDB: u=0x043B; break; /* CYRILLIC SMALL EL */
+  case 0xDC: u=0x043C; break; /* CYRILLIC SMALL EM */
+  case 0xDD: u=0x043D; break; /* CYRILLIC SMALL EN */
+  case 0xDE: u=0x043E; break; /* CYRILLIC SMALL O */
+  case 0xDF: u=0x043F; break; /* CYRILLIC SMALL PE */
+  case 0xE0: u=0x0440; break; /* CYRILLIC SMALL ER */
+  case 0xE1: u=0x0441; break; /* CYRILLIC SMALL ES */
+  case 0xE2: u=0x0442; break; /* CYRILLIC SMALL TE */
+  case 0xE3: u=0x0443; break; /* CYRILLIC SMALL U */
+  case 0xE4: u=0x0444; break; /* CYRILLIC SMALL EF */
+  case 0xE5: u=0x0445; break; /* CYRILLIC SMALL HA */
+  case 0xE6: u=0x0446; break; /* CYRILLIC SMALL TSE */
+  case 0xE7: u=0x0447; break; /* CYRILLIC SMALL CHE */
+  case 0xE8: u=0x0448; break; /* CYRILLIC SMALL SHA */
+  case 0xE9: u=0x0449; break; /* CYRILLIC SMALL SHCHA */
+  case 0xEA: u=0x044A; break; /* CYRILLIC SMALL HARD SIGN */
+  case 0xEB: u=0x044B; break; /* CYRILLIC SMALL YERU */
+  case 0xEC: u=0x044C; break; /* CYRILLIC SMALL SOFT SIGN */
+  case 0xED: u=0x044D; break; /* CYRILLIC SMALL E */
+  case 0xEE: u=0x044E; break; /* CYRILLIC SMALL YU */
+  case 0xEF: u=0x044F; break; /* CYRILLIC SMALL YA */
+  case 0xF0: u=0x2116; break; /* NUMERO SIGN */
+  case 0xF1: u=0x0451; break; /* CYRILLIC SMALL IO */
+  case 0xF2: u=0x0452; break; /* CYRILLIC SMALL DJE */
+  case 0xF3: u=0x0453; break; /* CYRILLIC SMALL GJE */
+  case 0xF4: u=0x0454; break; /* CYRILLIC SMALL UKRAINIAN IE */
+  case 0xF5: u=0x0455; break; /* CYRILLIC SMALL DZE */
+  case 0xF6: u=0x0456; break; /* CYRILLIC SMALL BYELORUSSIAN-UKRAINIAN I */
+  case 0xF7: u=0x0457; break; /* CYRILLIC SMALL YI */
+  case 0xF8: u=0x0458; break; /* CYRILLIC SMALL JE */
+  case 0xF9: u=0x0459; break; /* CYRILLIC SMALL LJE */
+  case 0xFA: u=0x045A; break; /* CYRILLIC SMALL NJE */
+  case 0xFB: u=0x045B; break; /* CYRILLIC SMALL TSHE */
+  case 0xFC: u=0x045C; break; /* CYRILLIC SMALL KJE */
+  case 0xFD: u=0x00A7; break; /* SECTION SIGN */
+  case 0xFE: u=0x045E; break; /* CYRILLIC SMALL SHORT U */
+  case 0xFF: u=0x045F; break; /* CYRILLIC SMALL DZHE */
+} break;
+
+  case 6: /* ISO 8859-6: Arabic */
+
+switch(iso)
+{ case 0xAC: u=0x060C; break; /* ARABIC COMMA */
+  case 0xBB: u=0x061B; break; /* ARABIC SEMICOLON */
+  case 0xBF: u=0x061F; break; /* ARABIC QUESTION MARK */
+  case 0xC1: u=0x0621; break; /* ARABIC HAMZA */
+  case 0xC2: u=0x0622; break; /* ARABIC ALEF WITH MADDA ABOVE */
+  case 0xC3: u=0x0623; break; /* ARABIC ALEF WITH HAMZA ABOVE */
+  case 0xC4: u=0x0624; break; /* ARABIC WAW WITH HAMZA ABOVE */
+  case 0xC5: u=0x0625; break; /* ARABIC ALEF WITH HAMZA BELOW */
+  case 0xC6: u=0x0626; break; /* ARABIC YEH WITH HAMZA ABOVE */
+  case 0xC7: u=0x0627; break; /* ARABIC ALEF */
+  case 0xC8: u=0x0628; break; /* ARABIC BEH */
+  case 0xC9: u=0x0629; break; /* ARABIC TEH MARBUTA */
+  case 0xCA: u=0x062A; break; /* ARABIC TEH */
+  case 0xCB: u=0x062B; break; /* ARABIC THEH */
+  case 0xCC: u=0x062C; break; /* ARABIC JEEM */
+  case 0xCD: u=0x062D; break; /* ARABIC HAH */
+  case 0xCE: u=0x062E; break; /* ARABIC KHAH */
+  case 0xCF: u=0x062F; break; /* ARABIC DAL */
+  case 0xD0: u=0x0630; break; /* ARABIC THAL */
+  case 0xD1: u=0x0631; break; /* ARABIC REH */
+  case 0xD2: u=0x0632; break; /* ARABIC ZAIN */
+  case 0xD3: u=0x0633; break; /* ARABIC SEEN */
+  case 0xD4: u=0x0634; break; /* ARABIC SHEEN */
+  case 0xD5: u=0x0635; break; /* ARABIC SAD */
+  case 0xD6: u=0x0636; break; /* ARABIC DAD */
+  case 0xD7: u=0x0637; break; /* ARABIC TAH */
+  case 0xD8: u=0x0638; break; /* ARABIC ZAH */
+  case 0xD9: u=0x0639; break; /* ARABIC AIN */
+  case 0xDA: u=0x063A; break; /* ARABIC GHAIN */
+  case 0xE0: u=0x0640; break; /* ARABIC TATWEEL */
+  case 0xE1: u=0x0641; break; /* ARABIC FEH */
+  case 0xE2: u=0x0642; break; /* ARABIC QAF */
+  case 0xE3: u=0x0643; break; /* ARABIC KAF */
+  case 0xE4: u=0x0644; break; /* ARABIC LAM */
+  case 0xE5: u=0x0645; break; /* ARABIC MEEM */
+  case 0xE6: u=0x0646; break; /* ARABIC NOON */
+  case 0xE7: u=0x0647; break; /* ARABIC HEH */
+  case 0xE8: u=0x0648; break; /* ARABIC WAW */
+  case 0xE9: u=0x0649; break; /* ARABIC ALEF MAKSURA */
+  case 0xEA: u=0x064A; break; /* ARABIC YEH */
+  case 0xEB: u=0x064B; break; /* ARABIC FATHATAN */
+  case 0xEC: u=0x064C; break; /* ARABIC DAMMATAN */
+  case 0xED: u=0x064D; break; /* ARABIC KASRATAN */
+  case 0xEE: u=0x064E; break; /* ARABIC FATHA */
+  case 0xEF: u=0x064F; break; /* ARABIC DAMMA */
+  case 0xF0: u=0x0650; break; /* ARABIC KASRA */
+  case 0xF1: u=0x0651; break; /* ARABIC SHADDA */
+  case 0xF2: u=0x0652; break; /* ARABIC SUKUN */
+} break;
+
+  case 7: /* ISO 8859-7: Greek */
+
+switch(iso)
+{ case 0xA1: u=0x02BD; break; /* MODIFIER REVERSED COMMA */
+  case 0xA2: u=0x02BC; break; /* MODIFIER APOSTROPHE */
+  case 0xAF: u=0x2015; break; /* HORIZONTAL BAR */
+  case 0xB4: u=0x0384; break; /* GREEK TONOS */
+  case 0xB5: u=0x0385; break; /* GREEK DIALYTIKA TONOS */
+  case 0xB6: u=0x0386; break; /* GREEK CAP ALPHA WITH TONOS */
+  case 0xB8: u=0x0388; break; /* GREEK CAP EPSILON WITH TONOS */
+  case 0xB9: u=0x0389; break; /* GREEK CAP ETA WITH TONOS */
+  case 0xBA: u=0x038A; break; /* GREEK CAP IOTA WITH TONOS */
+  case 0xBC: u=0x038C; break; /* GREEK CAP OMICRON WITH TONOS */
+  case 0xBE: u=0x038E; break; /* GREEK CAP UPSILON WITH TONOS */
+  case 0xBF: u=0x038F; break; /* GREEK CAP OMEGA WITH TONOS */
+  case 0xC0: u=0x0390; break; /* GREEK SMALL IOTA WITH DIALYTIKA AND TONOS */
+  case 0xC1: u=0x0391; break; /* GREEK CAP ALPHA */
+  case 0xC2: u=0x0392; break; /* GREEK CAP BETA */
+  case 0xC3: u=0x0393; break; /* GREEK CAP GAMMA */
+  case 0xC4: u=0x0394; break; /* GREEK CAP DELTA */
+  case 0xC5: u=0x0395; break; /* GREEK CAP EPSILON */
+  case 0xC6: u=0x0396; break; /* GREEK CAP ZETA */
+  case 0xC7: u=0x0397; break; /* GREEK CAP ETA */
+  case 0xC8: u=0x0398; break; /* GREEK CAP THETA */
+  case 0xC9: u=0x0399; break; /* GREEK CAP IOTA */
+  case 0xCA: u=0x039A; break; /* GREEK CAP KAPPA */
+  case 0xCB: u=0x039B; break; /* GREEK CAP LAMDA */
+  case 0xCC: u=0x039C; break; /* GREEK CAP MU */
+  case 0xCD: u=0x039D; break; /* GREEK CAP NU */
+  case 0xCE: u=0x039E; break; /* GREEK CAP XI */
+  case 0xCF: u=0x039F; break; /* GREEK CAP OMICRON */
+  case 0xD0: u=0x03A0; break; /* GREEK CAP PI */
+  case 0xD1: u=0x03A1; break; /* GREEK CAP RHO */
+  case 0xD3: u=0x03A3; break; /* GREEK CAP SIGMA */
+  case 0xD4: u=0x03A4; break; /* GREEK CAP TAU */
+  case 0xD5: u=0x03A5; break; /* GREEK CAP UPSILON */
+  case 0xD6: u=0x03A6; break; /* GREEK CAP PHI */
+  case 0xD7: u=0x03A7; break; /* GREEK CAP CHI */
+  case 0xD8: u=0x03A8; break; /* GREEK CAP PSI */
+  case 0xD9: u=0x03A9; break; /* GREEK CAP OMEGA */
+  case 0xDA: u=0x03AA; break; /* GREEK CAP IOTA WITH DIALYTIKA */
+  case 0xDB: u=0x03AB; break; /* GREEK CAP UPSILON WITH DIALYTIKA */
+  case 0xDC: u=0x03AC; break; /* GREEK SMALL ALPHA WITH TONOS */
+  case 0xDD: u=0x03AD; break; /* GREEK SMALL EPSILON WITH TONOS */
+  case 0xDE: u=0x03AE; break; /* GREEK SMALL ETA WITH TONOS */
+  case 0xDF: u=0x03AF; break; /* GREEK SMALL IOTA WITH TONOS */
+  case 0xE0: u=0x03B0; break; /* GREEK SMALL UPSILON WITH DIALYTIKA AND TONOS */
+  case 0xE1: u=0x03B1; break; /* GREEK SMALL ALPHA */
+  case 0xE2: u=0x03B2; break; /* GREEK SMALL BETA */
+  case 0xE3: u=0x03B3; break; /* GREEK SMALL GAMMA */
+  case 0xE4: u=0x03B4; break; /* GREEK SMALL DELTA */
+  case 0xE5: u=0x03B5; break; /* GREEK SMALL EPSILON */
+  case 0xE6: u=0x03B6; break; /* GREEK SMALL ZETA */
+  case 0xE7: u=0x03B7; break; /* GREEK SMALL ETA */
+  case 0xE8: u=0x03B8; break; /* GREEK SMALL THETA */
+  case 0xE9: u=0x03B9; break; /* GREEK SMALL IOTA */
+  case 0xEA: u=0x03BA; break; /* GREEK SMALL KAPPA */
+  case 0xEB: u=0x03BB; break; /* GREEK SMALL LAMDA */
+  case 0xEC: u=0x03BC; break; /* GREEK SMALL MU */
+  case 0xED: u=0x03BD; break; /* GREEK SMALL NU */
+  case 0xEE: u=0x03BE; break; /* GREEK SMALL XI */
+  case 0xEF: u=0x03BF; break; /* GREEK SMALL OMICRON */
+  case 0xF0: u=0x03C0; break; /* GREEK SMALL PI */
+  case 0xF1: u=0x03C1; break; /* GREEK SMALL RHO */
+  case 0xF2: u=0x03C2; break; /* GREEK SMALL FINAL SIGMA */
+  case 0xF3: u=0x03C3; break; /* GREEK SMALL SIGMA */
+  case 0xF4: u=0x03C4; break; /* GREEK SMALL TAU */
+  case 0xF5: u=0x03C5; break; /* GREEK SMALL UPSILON */
+  case 0xF6: u=0x03C6; break; /* GREEK SMALL PHI */
+  case 0xF7: u=0x03C7; break; /* GREEK SMALL CHI */
+  case 0xF8: u=0x03C8; break; /* GREEK SMALL PSI */
+  case 0xF9: u=0x03C9; break; /* GREEK SMALL OMEGA */
+  case 0xFA: u=0x03CA; break; /* GREEK SMALL IOTA WITH DIALYTIKA */
+  case 0xFB: u=0x03CB; break; /* GREEK SMALL UPSILON WITH DIALYTIKA */
+  case 0xFC: u=0x03CC; break; /* GREEK SMALL OMICRON WITH TONOS */
+  case 0xFD: u=0x03CD; break; /* GREEK SMALL UPSILON WITH TONOS */
+  case 0xFE: u=0x03CE; break; /* GREEK SMALL OMEGA WITH TONOS */
+} break;
+
+  case 8: /* ISO 8859-8: Hebrew */
+
+switch(iso)
+{ case 0xAA: u=0x00D7; break; /* MULTIPLICATION SIGN */
+  case 0xAF: u=0x203E; break; /* OVERLINE */
+  case 0xBA: u=0x00F7; break; /* DIVISION SIGN */
+  case 0xDF: u=0x2017; break; /* DOUBLE LOW LINE */
+  case 0xE0: u=0x05D0; break; /* HEBREW ALEF */
+  case 0xE1: u=0x05D1; break; /* HEBREW BET */
+  case 0xE2: u=0x05D2; break; /* HEBREW GIMEL */
+  case 0xE3: u=0x05D3; break; /* HEBREW DALET */
+  case 0xE4: u=0x05D4; break; /* HEBREW HE */
+  case 0xE5: u=0x05D5; break; /* HEBREW VAV */
+  case 0xE6: u=0x05D6; break; /* HEBREW ZAYIN */
+  case 0xE7: u=0x05D7; break; /* HEBREW HET */
+  case 0xE8: u=0x05D8; break; /* HEBREW TET */
+  case 0xE9: u=0x05D9; break; /* HEBREW YOD */
+  case 0xEA: u=0x05DA; break; /* HEBREW FINAL KAF */
+  case 0xEB: u=0x05DB; break; /* HEBREW KAF */
+  case 0xEC: u=0x05DC; break; /* HEBREW LAMED */
+  case 0xED: u=0x05DD; break; /* HEBREW FINAL MEM */
+  case 0xEE: u=0x05DE; break; /* HEBREW MEM */
+  case 0xEF: u=0x05DF; break; /* HEBREW FINAL NUN */
+  case 0xF0: u=0x05E0; break; /* HEBREW NUN */
+  case 0xF1: u=0x05E1; break; /* HEBREW SAMEKH */
+  case 0xF2: u=0x05E2; break; /* HEBREW AYIN */
+  case 0xF3: u=0x05E3; break; /* HEBREW FINAL PE */
+  case 0xF4: u=0x05E4; break; /* HEBREW PE */
+  case 0xF5: u=0x05E5; break; /* HEBREW FINAL TSADI */
+  case 0xF6: u=0x05E6; break; /* HEBREW TSADI */
+  case 0xF7: u=0x05E7; break; /* HEBREW QOF */
+  case 0xF8: u=0x05E8; break; /* HEBREW RESH */
+  case 0xF9: u=0x05E9; break; /* HEBREW SHIN */
+  case 0xFA: u=0x05EA; break; /* HEBREW TAV */
+} break;
+
+  case 9: /* ISO 8859-9: Latin5: west European without Icelandic */
+
+switch(iso)
+{
+  case 0xD0: u=0x011E; break; /* LATIN CAP G WITH BREVE */
+  case 0xDD: u=0x0130; break; /* LATIN CAP I WITH DOT ABOVE */
+  case 0xDE: u=0x015e; break; /* LATIN CAP S WITH CEDILLA */
+  case 0xF0: u=0x011f; break; /* LATIN SMALL G WITH BREVE */
+  case 0xFD: u=0x0131; break; /* LATIN SMALL DOTLESS I */
+  case 0xFE: u=0x015f; break; /* LATIN SMALL S WITH CEDILLA */
+} break;
+
+    }
+    return u;
+}
+
+/* ------------------------------------------------------------------------- */
+/*  (3) Unicode -> ZSCII and vice versa                                      */
+/*                                                                           */
+/*     Need not be rapid, as the results are mostly cached.                  */
+/*     Unicode chars which can't be fitted into ZSCII are converted to the   */
+/*     value 5 (the pad character used in the dictionary and elsewhere).     */
+/* ------------------------------------------------------------------------- */
+
+int zscii_defn_modified, zscii_high_water_mark;
+
+int32 zscii_to_unicode_grid[0x61];
+
+static void zscii_unicode_map(int zscii, int32 unicode)
+{   if ((zscii < 155) || (zscii > 251))
+    {   compiler_error("Attempted to map a Unicode character into the ZSCII \
+set at an illegal position");
+        return;
+    }
+    zscii_to_unicode_grid[zscii-155] = unicode;
+    zscii_defn_modified = TRUE;
+}
+
+int default_zscii_highset_sizes[] = { 69, 69, 81, 71, 82, 92, 48, 71, 27, 62 };
+
+int32 default_zscii_to_unicode_c01[]
+    = { /* (This ordering is important, unlike those for other char sets)
+           The 69 characters making up the default Unicode translation
+           table (see the Z-Machine Standard 1.0). */
+
+        0xe4, /* a-diaeresis */ 0xf6, /* o-diaeresis */ 0xfc, /* u-diaeresis */
+        0xc4, /* A-diaeresis */ 0xd6, /* O-diaeresis */ 0xdc, /* U-diaeresis */
+        0xdf, /* sz-ligature */ 0xbb, /* >> */ 0xab, /* << */
+        0xeb, /* e-diaeresis */ 0xef, /* i-diaeresis */ 0xff, /* y-diaeresis */
+        0xcb, /* E-diaeresis */ 0xcf, /* I-diaeresis */ 0xe1, /* a-acute */
+        0xe9, /* e-acute */ 0xed, /* i-acute */ 0xf3, /* o-acute */
+        0xfa, /* u-acute */ 0xfd, /* y-acute */ 0xc1, /* A-acute */
+        0xc9, /* E-acute */ 0xcd, /* I-acute */ 0xd3, /* O-acute */
+        0xda, /* U-acute */ 0xdd, /* Y-acute */ 0xe0, /* a-grave */
+        0xe8, /* e-grave */ 0xec, /* i-grave */ 0xf2, /* o-grave */
+        0xf9, /* u-grave */ 0xc0, /* A-grave */ 0xc8, /* E-grave */
+        0xcc, /* I-grave */ 0xd2, /* O-grave */ 0xd9, /* U-grave */
+        0xe2, /* a-circumflex */ 0xea, /* e-circumflex */
+        0xee, /* i-circumflex */ 0xf4, /* o-circumflex */
+        0xfb, /* u-circumflex */ 0xc2, /* A-circumflex */
+        0xca, /* E-circumflex */ 0xce, /* I-circumflex */
+        0xd4, /* O-circumflex */ 0xdb, /* U-circumflex */
+        0xe5, /* a-ring */ 0xc5, /* A-ring */
+        0xf8, /* o-slash */ 0xd8, /* O-slash */
+        0xe3, /* a-tilde */ 0xf1, /* n-tilde */ 0xf5, /* o-tilde */
+        0xc3, /* A-tilde */ 0xd1, /* N-tilde */ 0xd5, /* O-tilde */
+        0xe6, /* ae-ligature */ 0xc6, /* AE-ligature */
+        0xe7, /* c-cedilla */ 0xc7, /* C-cedilla */
+        0xfe, /* thorn */ 0xf0, /* eth */ 0xde, /* Thorn */ 0xd0, /* Eth */
+        0xa3, /* pound symbol */
+        0x0153, /* oe-ligature */ 0x0152, /* OE-ligature */
+        0xa1, /* inverted ! */ 0xbf /* inverted ? */ };
+
+int32 default_zscii_to_unicode_c2[]
+    = { /* The 81 accented letters in Latin2 */
+        0x0104, 0x0141, 0x013D, 0x015A, 0x0160, 0x015E, 0x0164, 0x0179,
+        0x017D, 0x017B, 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139,
+        0x0106, 0x00C7, 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD,
+        0x00CE, 0x010E, 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150,
+        0x00D6, 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162,
+        0x0105, 0x0142, 0x013E, 0x015B, 0x0161, 0x015F, 0x0165, 0x017A,
+        0x017E, 0x017C, 0x00DF, 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4,
+        0x013A, 0x0107, 0x00E7, 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B,
+        0x00ED, 0x00EE, 0x010F, 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4,
+        0x0151, 0x00F6, 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD,
+        0x0163 };
+
+int32 default_zscii_to_unicode_c3[]
+    = { /* The 71 accented letters in Latin3 */
+        0x0126, 0x0124, 0x0130, 0x015E, 0x011E, 0x0134, 0x017B, 0x0127,
+        0x0125, 0x0131, 0x015F, 0x011F, 0x0135, 0x017C, 0x00C0, 0x00C1,
+        0x00C2, 0x00C4, 0x010A, 0x0108, 0x00C7, 0x00C8, 0x00C9, 0x00CA,
+        0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D1, 0x00D2, 0x00D3,
+        0x00D4, 0x0120, 0x00D6, 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC,
+        0x016C, 0x015C, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E4, 0x010B,
+        0x0109, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED,
+        0x00EE, 0x00EF, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6,
+        0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D };
+
+int32 default_zscii_to_unicode_c4[]
+    = { /* The 82 accented letters in Latin4 */
+        0x0104, 0x0138, 0x0156, 0x0128, 0x013B, 0x0160, 0x0112, 0x0122,
+        0x0166, 0x017D, 0x0105, 0x0157, 0x0129, 0x013C, 0x0161, 0x0113,
+        0x0123, 0x0167, 0x014A, 0x017E, 0x014B, 0x0100, 0x00C1, 0x00C2,
+        0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, 0x010C, 0x00C9, 0x0118,
+        0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, 0x0110, 0x0145, 0x014C,
+        0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D8, 0x0172, 0x00DA, 0x00DB,
+        0x00DC, 0x0168, 0x016A, 0x00DF, 0x0101, 0x00E1, 0x00E2, 0x00E3,
+        0x00E4, 0x00E5, 0x00E6, 0x012F, 0x010D, 0x00E9, 0x0119, 0x00EB,
+        0x0117, 0x00ED, 0x00EE, 0x012B, 0x0111, 0x0146, 0x014D, 0x0137,
+        0x00F4, 0x00F5, 0x00F6, 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC,
+        0x0169, 0x016B };
+
+int32 default_zscii_to_unicode_c5[]
+    = { /* The 92 accented letters in Cyrillic */
+        0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408,
+        0x0409, 0x040A, 0x040B, 0x040C, 0x040E, 0x040F, 0x0410, 0x0411,
+        0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419,
+        0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421,
+        0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429,
+        0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431,
+        0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439,
+        0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441,
+        0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449,
+        0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x0451, 0x0452,
+        0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A,
+        0x045B, 0x045C, 0x045E, 0x045F };
+
+int32 default_zscii_to_unicode_c6[]
+    = { /* The 48 accented letters in Arabic */
+        0x060C, 0x061B, 0x061F, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625,
+        0x0626, 0x0627, 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D,
+        0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635,
+        0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642,
+        0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
+        0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x0651, 0x0652 };
+
+int32 default_zscii_to_unicode_c7[]
+    = { /* The 71 accented letters in Greek */
+        0x0384, 0x0385, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
+        0x038F, 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396,
+        0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E,
+        0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+        0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+        0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+        0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+        0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+        0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE };
+
+int32 default_zscii_to_unicode_c8[]
+    = { /* The 27 accented letters in Hebrew */
+        0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+        0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+        0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+        0x05E8, 0x05E9, 0x05EA };
+
+int32 default_zscii_to_unicode_c9[]
+    = { /* The 62 accented letters in Latin5 */
+        0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+        0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+        0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D8,
+        0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, 0x00E0,
+        0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8,
+        0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x011F,
+        0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F8, 0x00F9,
+        0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF };
+
+static void make_unicode_zscii_map(void)
+{   int i;
+
+    for (i=0; i<0x61; i++) zscii_to_unicode_grid[i] = '?';
+
+    zscii_high_water_mark
+        = default_zscii_highset_sizes[character_set_setting];
+
+    for (i=0; i<zscii_high_water_mark; i++)
+    {   switch(character_set_setting)
+        {   case 0:
+            case 1: zscii_unicode_map(i+155, default_zscii_to_unicode_c01[i]);
+                    break;
+            case 2: zscii_unicode_map(i+155, default_zscii_to_unicode_c2[i]);
+                    break;
+            case 3: zscii_unicode_map(i+155, default_zscii_to_unicode_c3[i]);
+                    break;
+            case 4: zscii_unicode_map(i+155, default_zscii_to_unicode_c4[i]);
+                    break;
+            case 5: zscii_unicode_map(i+155, default_zscii_to_unicode_c5[i]);
+                    break;
+            case 6: zscii_unicode_map(i+155, default_zscii_to_unicode_c6[i]);
+                    break;
+            case 7: zscii_unicode_map(i+155, default_zscii_to_unicode_c7[i]);
+                    break;
+            case 8: zscii_unicode_map(i+155, default_zscii_to_unicode_c8[i]);
+                    break;
+            case 9: zscii_unicode_map(i+155, default_zscii_to_unicode_c9[i]);
+                    break;
+        }
+    }
+    if (character_set_setting < 2) zscii_defn_modified = FALSE;
+    make_iso_to_alphabet_grid();
+}
+
+extern void new_zscii_character(int32 u, int plus_flag)
+{
+    if (u < 0 || u > 0xFFFF)
+        error("Zcharacter table cannot contain Unicode characters beyond $FFFF");
+    if (plus_flag == FALSE)
+        zscii_high_water_mark = 0;
+    if (zscii_high_water_mark == 0x61)
+        error("No more room in the Zcharacter table");
+    else zscii_unicode_map(155 + zscii_high_water_mark++, u);
+}
+
+extern void new_zscii_finished(void)
+{   make_iso_to_alphabet_grid();
+}
+
+extern int unicode_to_zscii(int32 u)
+{   int i;
+    if (u < 0x7f) return u;
+    for (i=0; i<zscii_high_water_mark; i++)
+        if (zscii_to_unicode_grid[i] == u) return i+155;
+    return 5;
+}
+
+extern int32 zscii_to_unicode(int z)
+{   if (z < 0x80) return z;
+    if ((z >= 155) && (z <= 251)) return zscii_to_unicode_grid[z-155];
+    return '?';
+}
+
+/* ------------------------------------------------------------------------- */
+/*  (4) Text -> Unicode                                                      */
+/*                                                                           */
+/*  This routine is not used for ordinary text compilation as it is too      */
+/*  slow, but it's useful for handling @ string escapes, or to avoid writing */
+/*  special code when speed is not especially required.                      */
+/*  Note that the two string escapes which can define Unicode are:           */
+/*                                                                           */
+/*      @..      where .. is an accent                                       */
+/*  and @{...}   where ... specifies a Unicode char in hexadecimal           */
+/*               (1 to 6 digits long)                                        */
+/*                                                                           */
+/*  If either syntax is malformed, an error is generated                     */
+/*  and the Unicode (= ISO = ASCII) character value of '?' is returned       */
+/*                                                                           */
+/*  In Unicode mode (character_set_unicode is true), this handles UTF-8      */
+/*  decoding as well as @-expansion. (So it's called when an '@' appears     */
+/*  *and* when a high-bit character appears.)                                */
+/* ------------------------------------------------------------------------- */
+
+int textual_form_length;
+
+extern int32 text_to_unicode(char *text)
+{   int i;
+
+    if (text[0] != '@')
+    {   if (character_set_unicode)
+        {   if (text[0] & 0x80) /* 8-bit */
+            {   switch (text[0] & 0xF0)
+                {   case 0xf0: /* 4-byte UTF-8 string */
+                        textual_form_length = 4;
+                        if ((text[0] & 0xf8) != 0xf0)
+                        {   error("Invalid 4-byte UTF-8 string.");
+                            return '?';
+                        }
+                        if ((text[1] & 0xc0) != 0x80 || (text[2] & 0xc0) != 0x80 || (text[3] & 0xc0) != 0x80)
+                        {   error("Invalid 4-byte UTF-8 string.");
+                            return '?';
+                        }
+                        return (text[0] & 0x07) << 18
+                            | (text[1] & 0x3f) << 12
+                            | (text[2] & 0x3f) << 6
+                            | (text[3] & 0x3f);
+                        break;
+                    case 0xe0: /* 3-byte UTF-8 string */
+                        textual_form_length = 3;
+                        if ((text[1] & 0xc0) != 0x80 || (text[2] & 0xc0) != 0x80)
+                        {   error("Invalid 3-byte UTF-8 string.");
+                            return '?';
+                        }
+                        return (text[0] & 0x0f) << 12
+                            | (text[1] & 0x3f) << 6
+                            | (text[2] & 0x3f);
+                        break;
+                    case 0xc0: /* 2-byte UTF-8 string */ 
+                    case 0xd0:
+                        textual_form_length = 2;
+                        if ((text[1] & 0xc0) != 0x80)
+                        {   error("Invalid 2-byte UTF-8 string.");
+                            return '?';
+                        }
+                        return (text[0] & 0x1f) << 6
+                            | (text[1] & 0x3f);
+                        break;
+                    default: /* broken */
+                        error("Invalid UTF-8 string.");
+                        textual_form_length = 1;
+                        return '?';
+                        break;
+                }
+            }
+            else /* nice 7-bit */
+            {   textual_form_length = 1;
+                return (uchar) text[0];
+            }
+        }
+        else
+        {
+            textual_form_length = 1;
+            return iso_to_unicode((uchar) text[0]);
+        }
+    }
+
+    if ((isdigit(text[1])) || (text[1] == '@'))
+    {   ebf_error("'@' plus an accent code or '@{...}'", text);
+        textual_form_length = 1;
+        return '?';
+    }
+
+    if (text[1] != '{')
+    {   for (i=0; accents[i] != 0; i+=2)
+            if ((text[1] == accents[i]) && (text[2] == accents[i+1]))
+            {   textual_form_length = 3;
+                return default_zscii_to_unicode_c01[i/2];
+            }
+
+        {   char uac[4];
+            uac[0]='@'; uac[1]=text[1]; uac[2]=text[2]; uac[3]=0;
+            error_named("No such accented character as", uac);
+        }
+    }
+    else
+    {   int32 total = 0;
+        int d=0; i=1;
+        while (text[++i] != '}')
+        {   if (text[i] == 0)
+            {   error("'@{' without matching '}'");
+                total = '?'; break;
+            }
+            if (i == 8)
+            {   error("At most six hexadecimal digits allowed in '@{...}'");
+                total = '?'; break;
+            }
+            d = character_digit_value[(uchar)text[i]];
+            if (d == 127)
+            {   error("'@{...}' may only contain hexadecimal digits");
+                total = '?'; break;
+            }
+            total = total*16 + d;
+        }
+        while ((text[i] != '}') && (text[i] != 0)) i++;
+        if (text[i] == '}') i++;
+        textual_form_length = i;
+        return total;
+    }
+
+    textual_form_length = 1;
+    return '?';
+}
+
+/* ------------------------------------------------------------------------- */
+/*  (5) Zscii -> Text                                                        */
+/*                                                                           */
+/*  Used for printing out dictionary contents into the text transcript file  */
+/*  or on-screen (in response to the Trace dictionary directive).            */
+/*  In either case, output uses the same ISO set as the source code.         */
+/* ------------------------------------------------------------------------- */
+
+extern void zscii_to_text(char *text, int zscii)
+{   int i;
+    int32 unicode;
+
+    if ((zscii < 0x100) && (zscii_to_iso_grid[zscii] != 0))
+    {   text[0] = zscii_to_iso_grid[zscii]; text[1] = 0; return;
+    }
+
+    unicode = zscii_to_unicode(zscii);
+    for (i=0;i<69;i++)
+        if (default_zscii_to_unicode_c01[i] == unicode)
+        {   text[0] = '@';
+            text[1] = accents[2*i];
+            text[2] = accents[2*i+1];
+            text[3] = 0; return;
+        }
+    sprintf(text, "@{%x}", unicode);
+}
+
+/* ========================================================================= */
+
+extern char *name_of_iso_set(int s)
+{   switch(s)
+    {   case 1: return "Latin1";
+        case 2: return "Latin2";
+        case 3: return "Latin3";
+        case 4: return "Latin4";
+        case 5: return "Cyrillic";
+        case 6: return "Arabic";
+        case 7: return "Greek";
+        case 8: return "Hebrew";
+        case 9: return "Latin5";
+    }
+    return "Plain ASCII";
+}
+
+extern void change_character_set(void)
+{   make_source_to_iso_grid();
+    make_unicode_zscii_map();
+}
+
+/* ------------------------------------------------------------------------- */
+/*   Case translation of standard Roman letters within ISO                   */
+/* ------------------------------------------------------------------------- */
+
+extern void make_lower_case(char *str)
+{   int i;
+    for (i=0; str[i]!=0; i++)
+        if ((((uchar)str[i])<128) && (isupper(str[i]))) str[i]=tolower(str[i]);
+}
+
+extern void make_upper_case(char *str)
+{   int i;
+    for (i=0; str[i]!=0; i++)
+        if ((((uchar)str[i])<128) && (islower(str[i]))) str[i]=toupper(str[i]);
+}
+
+/* ========================================================================= */
+/*   Data structure management routines                                      */
+/* ------------------------------------------------------------------------- */
+
+extern void init_chars_vars(void)
+{   int n;
+    for (n=0; n<128; n++) character_digit_value[n] = 127;
+    character_digit_value['0'] = 0;
+    character_digit_value['1'] = 1;
+    character_digit_value['2'] = 2;
+    character_digit_value['3'] = 3;
+    character_digit_value['4'] = 4;
+    character_digit_value['5'] = 5;
+    character_digit_value['6'] = 6;
+    character_digit_value['7'] = 7;
+    character_digit_value['8'] = 8;
+    character_digit_value['9'] = 9;
+    character_digit_value['a'] = 10;
+    character_digit_value['b'] = 11;
+    character_digit_value['c'] = 12;
+    character_digit_value['d'] = 13;
+    character_digit_value['e'] = 14;
+    character_digit_value['f'] = 15;
+    character_digit_value['A'] = 10;
+    character_digit_value['B'] = 11;
+    character_digit_value['C'] = 12;
+    character_digit_value['D'] = 13;
+    character_digit_value['E'] = 14;
+    character_digit_value['F'] = 15;
+
+    strcpy((char *) alphabet[0], "abcdefghijklmnopqrstuvwxyz");
+    strcpy((char *) alphabet[1], "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+    strcpy((char *) alphabet[2], " ^0123456789.,!?_#'~/\\-:()");
+
+    alphabet_modified = FALSE;
+
+    for (n=0; n<78; n++) alphabet_used[n] = 'N';
+
+    change_character_set();
+}
+
+extern void chars_begin_pass(void)
+{
+}
+
+extern void chars_allocate_arrays(void)
+{
+}
+
+extern void chars_free_arrays(void)
+{
+}
+
+/* ========================================================================= */