<details><summary>Table of Contents</summary>

- [Introduction](#Introduction)
- [Common Attributes](#Common-Attributes)
- [The :INTRANS Block](#The-INTRANS-Block)
- [The :OUTTRANS Block](#The-OUTTRANS-Block)
</details>

#
Introduction
------------

This page is used to describe elements of :DEVICE, :DRIVER and :FONT blocks that are common to two or more of them.

This section exists to force the Wiki to provide a Table of Contents (which requires more than three sections).

Common Attributes
-----------------

The attributes **defined\_name** and **member\_name** are found in :DEVICE blocks, :DRIVER blocks, and :FONT blocks, and are treated identically in each case.

These attributes are used to identify the specific block they are in to wgml and gendev. They do not appear in the same binary member file as the rest of that block's entries (although the attribute **member\_name** is used as the name of that file): they appear instead in the directory file entry created when the source file is processed. They are both character strings.

These attributes are required in the sense that, if they are missing, gendev produces this error message:

    AT--001: Required attribute not found.

gendev does not, however, object if either or both are given as empty strings.

If the attribute **defined\_name** is an empty string, then the field **defined\_name** in the directory file consists in the single byte "0x00" which wgml will match with an empty string used in either of two contexts:

-   as the value of the command-line option DEVICE; and
-   as the value of the attribute **driver\_name** in a :DEVICE block.

The restrictions imposed by gendev on the attributes **font** and **fontname** in all cases except the :UNDERSCORE block made it impossible to verify that an empty string for these attributes would match a font with an empty string for the value of attribute **defined\_name** (see the discussion at the end of [The :UNDERSCORE Block](WGML-Device-File-Blocks#The-UNDERSCORE-Block) for further speculation on the effect of an empty string as the value of attribute **font** in an :UNDERSCORE block).

If the attribute **member\_name** is empty, then a gendev error occurs, so an empty field **member\_name** should never be found.

The functions in "copdir.c" accept an empty string for field **defined\_name** but treat an empty string for **member\_name** as an error condition.

The attribute **defined\_name** has a documented limit of 78 characters.

The attribute **member\_name** has some interesting properties when used with the DOS version of gendev 4.1 (and so when used with the FAT file system):

-   if it does not contain a **.**, then the first eight characters are taken as the file name and ".cop" is used as the extension; the directory file entry, however, will show all the characters given as the file name (and no extension).
-   if it does contain a **.**, then the first eight characters before the **.** are taken as the file name and the first three characters after the **.** are taken as the extension; the directory file entry, however, will show all the characters given.
-   if it contains more than one **.**, then this error is produced:

<!-- -->

    IO--004: Output operation failed.

If an empty string was given for the attribute **member\_name**, then error IO--004 occurs. This indicates that gendev does not check the value of the attribute to screen out an empty string but rather that the file system rejects a nonexistent filename.

When gendev and wgml are implemented, it will be necessary to further explore the file-naming behavior associated with the attribute **member\_name**.

The :INTRANS Block
------------------

The description of the :INTRANS block given in the [WGML 4 Reference](WGML-References#reference1) is still correct:

    :INTRANS.
       font-character input-translation
    :eINTRANS.

This block does not have attributes. Both **font-character** and **input-translation** are character values.

An empty :INTRANS block (one with no entries) is the same as no :INTRANS block at all: gendev ignores it.

gendev 3.33 enforces a limit of "$ff" on the character values with this message:

    SN--001: Number is too large or contains invalid characters

gendev 4.1 will accept, for example "$feff" but treats it as if it were "$ff". There is, then, no point in using values larger than $ff.

If an :INTRANS block with more than two characters on a line is input, that is, one like this:

    :INTRANS.
       b c d
    :eINTRANS.

then gendev accepts the input but produces *exactly* the same encoding that

    :INTRANS.
       b c
    :eINTRANS.

produces. The :INTRANS block, then, cannot be written on one line, at least if it has more than one entry.

Multiple :INTRANS blocks, whether identical or different, are allowed in the source file. They are merged into a single entry in the binary file. If the same character is given for translation in more than one block, the translation in the *last* block will be used:

    :INTRANS.
       b c
    :eINTRANS.

    :INTRANS.
       b c
    :eINTRANS.

maps 'b' to 'c' and

    :INTRANS.
       b c
    :eINTRANS.

    :INTRANS.
       d c
    :eINTRANS.

maps both 'b' and 'd' to 'c' but

    :INTRANS.
       b c
    :eINTRANS.

    :INTRANS.
       b d
    :eINTRANS.

maps 'b' to 'd' in the binary file.

The corresponding struct in the binary file is:

    IntransBlock {
       uint8_t designator = 0x81;
       uint8_t count = 0x00;
       uint8_t table[0x100];
    };

The value of the field **designator** is always "0x81".

The value of the field **count** is always "0x00".

If the field **table** is treated as an array, then, given the first mapping above, table\['b'\] would be 'c', as would table\['c'\]. The effect is to create an array of 0x100 byte values, each entry in which is equal to its index, and then, for each **font-character**, to place the **input-translation** character into table\[font-character\]. No instances of any other form are known.

The IntransBlock, when present, is part of the [TranslationBlock](WGML-Device-File-Blocks#The-TranslationBlock-Structure) (for binary device files) or the [CharacterDescriptionBlock](WGML-Font-File-Blocks#The-CharacterDescriptionBlock-Structure) (for binary font files). It has the structure shown above in either case.

The :OUTTRANS Block
-------------------

The description of the :OUTTRANS block given in [WGML 4 Reference](WGML-References#reference1) is still correct:

    :OUTTRANS.
       font-character output-translation
    :eOUTTRANS.

This block does not have attributes. Both the **font-character** and the **output-translation** are character values.

The **output-translation** can be either a single character value or a sequence of single character values separated by spaces.

An empty :OUTTRANS block (one with no entries) is the same as no :OUTTRANS block at all: gendev ignores it.

gendev 3.33 enforces a limit of "$ff" on each character value with this message:

    SN--001: Number is too large or contains invalid characters

gendev 4.1 behaves differently when, for example, "$feff" is used as the **font-character** and when it is used as one of the characters in the **output-translation**:

1.  If the value of the **font-character** is "$feff", a GP-fault results.
2.  If the value of one of the characters in the **output-translation** is "$feff", it is treated as if it were "$ff".

So there is no point to using character values higher than "$ff".

Multiple :OUTTRANS blocks, whether identical or different, are allowed in the source file. They are merged into a single entry in the binary file. If the same character is given for translation in more than one block, the translation in the last block will be used:

    :OUTTRANS.
       ( \ (
    :eOUTTRANS.

    :OUTTRANS.
      ( \ (
    :eOUTTRANS.

maps '(' to '\\(' and

    :OUTTRANS.
       ( \ (
    :eOUTTRANS.

    :OUTTRANS.
       { \ (
    :eOUTTRANS.

maps both '(' and '{' to '\\(' but

    :OUTTRANS.
       ( \ (
    :eOUTTRANS.

    :OUTTRANS.
       ( \ {
    :eOUTTRANS.

maps '(' to '\\{' in the binary file.

Since gendev takes all but the first character to be the **output-translation** for the first character, it follows that the :OUTTRANS block cannot be written on one line, at least, not if it contains more than one entry.

When no line of the :OUTTRANS block contains more than one character in the **output-translation**, then the corresponding struct in the binary file is:

    OuttransBlock {
       uint8_t designator = 0x81;
       uint8_t count = 0x00;
       uint8_t table[0x100];
    };

The value of the field **designator** is always "0x81".

The value of the field **count** is always "0x00".

If the field **table** is treated as an array, then, given the first mapping above, table\['b'\] would be 'c', as would table\['c'\]. The effect is to create an array of 0x100 byte values, each entry in which is equal to its index, and then, for each **font-character**, to place the **input-translation** character into table\[font-character\].

This is identical to the struct used for the [IntransBlock](#The-INTRANS-Block).

If at least one line of the :OUTTRANS block contains more than one character in the **output-translation**, then the corresponding struct in the binary file is:

    OuttransBlock {
        uint8_t      designator = 0x82;
        uint8_t      count;
        uint16_t     table[0x100];
        OuttransData translations[count]
    };

The value of the field **designator** is always 0x82.

The field **count** is an 8-bit unsigned integer and its value is always identical to the value of the field **TranslationBlock.data\_count**. The value of the field **count** is the number of bytes in the field **data**. Although the upper bound of field **count** has not been determined, the size of **translations** is almost certainly limited to $FF at most.

The field **table** consists of 0x100 two-byte entries:

1.  If a character is not being translated, then the first byte is the character itself (the value of the index if the table is regarded as an array) and the second byte is "0x00".
2.  If a character is being translated to a *single character*, then the first byte is the character it is to be translated to and the second byte is "0x00".
3.  If a character is being translated to *more than one character*, the first byte is the offset into the data to the beginning of the output characters to be used. The second byte is "0x82".

The field **translations** is an array of these structs:

    OuttransData {
       uint8_t  count;
       uint8_t  data[length];
    }

The fields **count** and **data** together encode the **output-translation**.

Something odd happens when these conditions are satisfied:

-   More than one :OUTTRANS block exists.
-   The same **font-character** appears in more than one :OUTTRANS block with a translation to more than one character.

What happens is that all entries in field **translations** but the last entry for that **font-character** contain the bytes "0x03 0x50 0x0c 0xff" (which is an OuttransData struct with a count of "0x03" and a translation value of "0x50 0x0c 0xff"). This happens whether the **output-translation**s for the **font-character** are the same or different. In the field **table**, an offset to this sort of entry is never found.

It is unclear why this sort of entry is needed. Since it is four bytes in length, the data area and all affected offsets must be adjusted if the former output-translation had either more or less than 4 bytes, so why not just replace it with the new value? Or remove it entirely and put the new one at the end of the table?

The OuttransBlock, when present, is part of the [TranslationBlock](WGML-Device-File-Blocks#The-TranslationBlock-Structure) (for binary device files) or the [CharacterDescriptionBlock](WGML-Font-File-Blocks#The-CharacterDescriptionBlock-Structure) (for binary font files). It has the structure shown above in either case.
