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

- [The Attributes](#the-attributes)
- [The CharacterDescriptionBlock Structure](#the-characterdescriptionblock-structure)
- [The :INTRANS Block](#the-intrans-block)
- [The :OUTTRANS Block](#the-outtrans-block)
- [The :WIDTH Block](#the-width-block)
</details>

#
The Attributes
--------------

The description of the attribtures in the [WGML 4 Reference](WGML-References#reference1) is modified by the README file produceable from the [WGML 3.33 Update](WGML-References#reference2) with only one note:

    The mono_space_width attribute in :FONT has been removed.

All of the other attributes listed in [WGML 4 Reference](WGML-References#reference1) were observed in existing :FONT blocks.

Thus, the Attributes are:

    defined_name
    member_name
    font_out_name1
    font_out_name2
    line_height
    line_space
    scale_basis
    scale_min
    scale_max
    char_width

Although the [WGML 4 Reference](WGML-References#reference1) states:

    The attributes of the font block must all be specified.

This is not, in fact, correct.

These attributes are required:

-   defined\_name
-   member\_name
-   char\_width

If they are not present, then this error message results:

    AT--001: Required attribute not found

At least one of these attributes must appear:

-   line\_height
-   scale\_basis

If neither appears, then this somewhat-unintelligible error message is presented by gendev 4.1:

    SN--078: The line_height attribute must be specified
             if the scale_basis

Both may appear, and either or both may have a zero or a non-zero value, without any objection from gendev 4.1. Apparently, the requirement is that at least one of **line\_height** and **scale\_basis** be present, even if the value matches the default value of "0".

These attributes are optional:

-   font\_out\_name1
-   font\_out\_name2
-   line\_space
-   scale\_min
-   scale\_max

The attributes **defined\_name** and **member\_name** are discussed in [Common Attributes](WGML-Common-File-Blocks#Common-Attributes).

The attributes **font\_out\_name1** and **font\_out\_name2** are character strings, and an empty string is allowed. The remaining attributes are non-negative integers: **0** is allowed, but a negative value produces this error message:

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

This error message also results if these upper limits are exceeded:

-   For version 3.33 of gendev, for attributes **scale\_basis**, **scale\_min**, and **scale\_max**, values above $7FFFFFFF.
-   For version 3.33 of gendev, for attributes **line\_height**, **line\_space**, and **char\_width**, values above $CCCF.
-   For version 4.1 of gendev, for all numerical attributes, values above $7FFFFFFF.

If the value of the attribute **char\_width**, in version 3.33, is greater than $FF, then only the lower-order byte will be used in any [WidthBlock](#The-WIDTH-Block). There is, then, no point in version 3.33 in specifying a value larger than $FF for this attribute.

Regardless of their order in the source file, the attributes are encoded in the binary file this way:

    Attributes {
        uint8_t  font_out_name1_length;
        uint8_t  font_out_name1[font_out_name1_length];
        uint8_t  font_out_name2_length;
        uint8_t  font_out_name2[font_out_name2_length];
        FontData fontdata
    };

If the corresponding attribute is not present, or if it is given an empty string as its value, then the empty string in the binary file will be parsed as a NULL pointer.

For version 3.33 files, the FontData structure is:

    FontData {
        uint16_t designator = 0x1700;
        uint16_t line_height
        uint16_t line_space
        uint32_t scale_basis
        uint32_t scale_min
        uint32_t scale_max
        uint16_t char_width
    };

The default values for the optional attributes are:

-   font\_out\_name1: 0x00 (ie, a length byte of 0)
-   font\_out\_name2: 0x00 (ie, a length byte of 0)
-   line\_height: 0x0000
-   line\_space: 0x0000
-   scale\_basis: 0x00000000
-   scale\_min: 0x00000000
-   scale\_max: 0x00000000

For version 4.1 files, the FontData structure is:

    FontData {
        uint16_t designator = 0x1D00;
        uint32_t line_height
        uint32_t line_space
        uint32_t scale_basis
        uint32_t scale_min
        uint32_t scale_max
        uint32_t char_width
    };

The default values for the optional attributes are:

-   font\_out\_name1: 0x00 (ie, a length byte of 0)
-   font\_out\_name2: 0x00 (ie, a length byte of 0)
-   line\_height: 0x00000000
-   line\_space: 0x00000000
-   scale\_basis: 0x00000000
-   scale\_min: 0x00000000
-   scale\_max: 0x00000000

The designators can be used to determine which structure is present in the binary file.

The CharacterDescriptionBlock Structure
---------------------------------------

An IntransBlock will be present whenever a non-empty :INTRANS block is found in the source file.

An OuttransBlock will be present whenever a non-empty :OUTTRANS block is found in the source file.

There are two sizes for the OuttransBlock, which will be used below when appropriate:

-   a 1-byte OuttransBlock is an array of 0x100 uint8\_t values;
-   a 2-byte OuttransBlock is an array of 0x100 uint16\_t values.

A WidthBlock will be present under these conditions:

-   A non-empty :WIDTH block is present and at least one width value differs from the value of attribute **char\_width**.
-   For version 3.33, the value of **char\_width** is greater than $8000.

This does mean that, for version 3.33, the binary file can have a WidthBlock even if there are no non-empty :WIDTH blocks in the source file.

There are also three sizes for these blocks, which will be used below when appropriate:

-   a 1-byte block is an array of 0x100 uint8\_t values;
-   a 2-byte block is an array of 0x100 uint16\_t values; and
-   a 4-byte block is an array of 0x100 uint32\_t values.

Note that the IntransBlock only comes in one variety: the 1-byte IntransBlock. To avoid implying otherwise, no size will be indicated below for the IntransBlock.

The CharacterDescriptionBlock has eight different forms for eight different situations:

1.  There is neither an IntransBlock, nor an OuttransBlock nor a WidthBlock present.
2.  An IntransBlock is present, but an OuttransBlock is not and a WidthBlock is not.
3.  An OuttransBlock is present, but an IntransBlock is not and a WidthBlock is not.
4.  A WidthBlock is present, but an IntransBlock is not and an OuttransBlock is not.
5.  An IntransBlock and an OuttransBlock are present, but a WidthBlock is not present.
6.  An OuttransBlock and a WidthBlock are present, but an IntransBlock is not present.
7.  An IntransBlock and a WidthBlock are present, but an OuttransBlock is not present.
8.  An IntransBlock, an OuttransBlock, and a WidthBlock are present.

When there is neither an IntransBlock, nor an OuttransBlock nor a WidthBlock present, the struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag     = 0x00;
        uint8_t       width_flag    = 0x01;
        uint8_t       data_count    = 0x00;
        uint8_t       outtrans_flag = 0x00;
        uint8_t       intrans_flag  = 0x00;
    };

These fields appear in all CharacterDescriptionBlock forms.

When no WidthBlock is present, the value of the field **size\_flag** is always "0x00".

When a WidthBlock is present, the value of the field **size\_flag** varies:

-   the value "0x01" indicates that a 1-byte WidthBlock is present;
-   in version 3.33, the value "0x00" indicates that a 2-byte WidthBlock is present; and
-   in version 4.1, the value "0x00" indicates that a 4-byte WidthBlock is present.

The value of the field **width\_flag** varies:

-   the value "0x00" indicates that a WidthBlock is present; and
-   the value "0x01" indicates that a WidthBlock is not present.

The value of the field **data\_count** is the number of bytes required to encode the output-translation sequences in the :OUTTRANS block; if there is no OuttransBlock present or if a 1-byte OuttransBlock is present, then the value will be "0x00".

The value of the field **outtrans\_flag** varies:

-   the value "0x00" indicates that an OuttransBlock is not present;
-   the value "0x01" indicates that a 1-byte OuttransBlock is present; and
-   the value "0x02" indicates that a 2-byte OuttransBlock is present.

The value of the field **intrans\_flag** varies:

-   the value "0x00" indicates that an IntransBlock is not present; and
-   the value "0x01" indicates that an IntransBlock is present.

When an IntransBlock is present, but an OuttransBlock is not and a WidthBlock is not, the struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag     = 0x00;
        uint8_t       width_flag    = 0x01;
        uint8_t       data_count    = 0x00;
        uint8_t       outtrans_flag = 0x00;
        uint8_t       intrans_flag  = 0x01;
        IntransBlock  intrans;
    };

where IntransBlock is described in [The :INTRANS Block](WGML-Common-File-Blocks#The-INTRANS-Block).

When an OuttransBlock is present, but an IntransBlock is not and a WidthBlock is not, the struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag     = 0x00;
        uint8_t       width_flag    = 0x01;
        uint8_t       data_count;
        uint8_t       outtrans_flag;
        uint8_t       intrans_flag  = 0x00;
        OuttransBlock outtrans;
    };

where OuttransBlock is described in [The :OUTTRANS Block](WGML-Common-File-Blocks#The-OUTTRANS-Block).

When a WidthBlock is present, but an IntransBlock is not and an OuttransBlock is not, the struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag;
        uint8_t       width_flag    = 0x00;
        uint8_t       data_count    = 0x00;
        uint8_t       outtrans_flag = 0x00;
        uint8_t       intrans_flag  = 0x00;
        WidthBlock    width;
    };

The WidthBlock is described in [The :WIDTH Block](#The-WIDTH-Block).

When an IntransBlock and an OuttransBlock are present, but a WidthBlock is not present, the struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag     = 0x00;
        uint8_t       width_flag    = 0x01;
        uint8_t       data_count;
        uint8_t       outtrans_flag;
        uint8_t       intrans_flag  = 0x01;
        IntransBlock  intrans;
        OuttransBlock outtrans;
    };

When an OuttransBlock and a WidthBlock are present, but an IntransBlock is not present, the struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag;
        uint8_t       width_flag    = 0x00;
        uint8_t       data_count;
        uint8_t       outtrans_flag;
        uint8_t       intrans_flag  = 0x00;
        OuttransBlock outtrans;
        WidthBlock    width;
    };

When an IntransBlock and a WidthBlock are present, but an OuttransBlock is not present, the corresponding struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag;
        uint8_t       width_flag    = 0x00;
        uint8_t       data_count    = 0x00;
        uint8_t       outtrans_flag = 0x00;
        uint8_t       intrans_flag  = 0x01;
        IntransBlock  intrans;
        WidthBlock    width;
    };

When an IntransBlock, an OuttransBlock, and a WidthBlock are present, the corresponding struct in the binary file will be:

    CharacterDescriptionBlock {
        uint8_t       size_flag;
        uint8_t       width_flag    = 0x00;
        uint8_t       data_count;
        uint8_t       outtrans_flag;
        uint8_t       intrans_flag  = 0x01;
        IntransBlock  intrans;
        OuttransBlock outtrans;
        WidthBlock    width;
    };

An IntransBlock contains 0x102 bytes. An OuttransBlock contains either 0x102 bytes (if the value of the field **outtrans\_flag** is 0x01) or 0x202 bytes plus the value of field **data\_count** bytes(if the value of the field **outtrans\_flag** is 0x02). A WidthBlock contains either 0x102 bytes (if the value of the field **size\_flag** is "0x01"), 0x202 (if the value of the field **size\_flag** is "0x00" and the version is 3.33), or 0x402 (if the value of the field **size\_flag** is "0x00" and the version is 4.1). Thus, every form of CharacterDescriptionBlock allows computation of the number of bytes in that CharacterDescriptionBlock.

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

This block is described in [The :INTRANS Block](WGML-Common-File-Blocks#The-INTRANS-Block).

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

This block is described in [The :OUTTRANS Block](WGML-Common-File-Blocks#The-OUTTRANS-Block).

The :WIDTH Block
----------------

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

    :WIDTH.
       font-character character-width
    :eWIDTH.

This block does not have attributes. The **font-character** is a character value, and the **character\_width** must be a non-negative integer; if a character is not listed, the value of the attribute **char\_width** is used.

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

The version 3.33 gendev enforces a limit of "$ff" on the values of the **font\_character** with this message:

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

The version 4.1 gendev GP-faults for values of the **font\_character** greater than "$ff".

For both versions, prefixing the **character\_width** value with **$** (that is, using a hexadecimal value) produces this error message:

    SN--009: Width value must be an integer number

The minimum value allowed for the **character\_width** is "0", which does appear in the binary file if used in the source. The maximum value depends on the version:

-   Version 3.33: 32769 (0x8001); however, values that large are reduced to the least-significant byte (0x01). 32767 (0x7FFF) is the largest value that preserves the value entered.
-   Version 4.1: 2147483647 (0x7FFF) is the maximum accepted. The full value entered is preserved.

Multiple :WIDTH 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 a width in more than one block, the width given in the last block will be used:

    :WIDTH.
       b 5
    :eWIDTH.

    :WIDTH.
      b 5
    :eWIDTH.

assigns the width "5" to 'b'

    :WIDTH.
       b 5
    :eWIDTH.

    :WIDTH.
      d 5
    :eWIDTH.

assigns the width "5" to both 'b' and 'd' but

    :WIDTH.
       b 5
    :eWIDTH.

    :WIDTH.
      b 10
    :eWIDTH.

assigns the width "10" to 'b' in the binary file.

The struct used in the binary file does not depend on the version nearly so much as it depends on the values of the attribute **char\_width** and the largest **character\_width** value.

This struct is used in the binary file for either version:

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

The field **designator** has the same value as the corresponding field in the [IntransBlock](WGML-Common-File-Blocks#The-INTRANS-Block).

The field **count** has the same value as the corresponding field in the [IntransBlock](WGML-Common-File-Blocks#The-INTRANS-Block).

The field **table** is an array consisting of 100 bytes, and so this struct will be referred to as the 1-byte WidthBlock.

The 1-byte WidthBlock is used under these conditions:

-   For version 3.33, it is used when the largest **character\_width** value will fit into one byte or is larger than 32767 (0x7FFF), in which case only the lower-order byte is used; the size of the attribute **char\_width** does not matter.
-   For version 4.1, it is used when each of the value of **char\_width** and the largest **character\_width** value will fit into one byte.

This struct is used in the binary file for version 3.33 only:

    WidthBlock {
        uint8_t  designator = 0x82;
        uint8_t  count = 0x00;
        uint16_t table[0x100];
    };

The field **designator** has the same value as the corresponding field in the [OuttransBlock](WGML-Common-File-Blocks#The-OUTTRANS-Block).

The value of the field **count** is always "0x00", presumably because the WidthBlock has no field **data** as the corresponding struct does in the [OuttransBlock](WGML-Common-File-Blocks#The-OUTTRANS-Block).

The table is an array consisting of 100 pairs of bytes, and so this struct will be referred to as the 2-byte WidthBlock.

The 2-byte WidthBlock is used under these conditions:

-   The binary file is version 3.33.
-   At least one value of **character\_width** will not fit into a single byte and the value is no greater than 32767 (0x7FFF).
-   The size of the attribute **char\_width** does not matter.

The attribute **char\_width**, in version 3.33, is a two-byte value, but only the lower-order byte is used as the default value in the table. This applies even when the 2-byte WidthBlock is used: the upper byte of the value of the attribute **char\_width** is replaced with a null (0x00). Thus, in version 3.33, attribute **char\_width** is effectively limited to a maximum value of "$FF".

If no non-empty :WIDTH blocks are found in the source file but the value of attribute **char\_width** is greater than $7fff, then a 1-byte WidthBlock in which each byte contains (the lower-order byte of) the value of **char\_width** will be present in the binary file.

This struct is used in the binary file for version 4.1 only:

    WidthBlock {
        uint8_t  designator = 0x84;
        uint8_t  count = 0x01;
        uint32_t table[0x100];
    };

The field **designator** always has the value "0x84".

The value of the field **count** is always "0x01"; it is so-named by analogy with the other WidthBlock structs.

The table is an array consisting of 100 four-byte values, and so this struct will be referred to as the 4-byte WidthBlock.

The 4-byte WidthBlock is used under these conditions:

-   The binary file is version 4.1.
-   Either the value of the attribute **char\_width** or at least one value of **character\_width** will not fit into a single byte and the value is no greater than 2147483647 (0x7FFFFFFF).

The table is only present when at least one non-empty :WIDTH block is found in the source file. When it is present, entries not listed in any :WIDTH block use the full four-byte value of attribute **char\_width** (which has a maximum value of $7FFFFFFF).
