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

- [The Attributes](#the-attributes)
- [The :BOX Block](#the-box-block)
- [The :DEFAULTFONT Block](#the-defaultfont-block)
- [The :DEVICEFONT Block](#the-devicefont-block)
- [The FontAttribute Structure](#the-fontattribute-structure)
- [The :FONTPAUSE Block](#the-fontpause-block)
- [The :INTRANS Block](#the-intrans-block)
- [The :OUTTRANS Block](#the-outtrans-block)
- [The PagegeometryBlock Struct](#the-pagegeometryblock-struct)
- [The :PAGEOFFSET Block](#the-pageoffset-block)
- [The :PAGESTART Block](#the-pagestart-block)
- [The :PAUSE Block](#the-pause-block)
- [The TranslationBlock Structure](#the-translationblock-structure)
- [The :UNDERSCORE Block](#the-underscore-block)
</details>

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

The first items in the :DEVICE block must be these attributes:

    defined_name
    member_name
    driver_name
    output_suffix
    output_name
    page_width
    page_depth
    horizontal_base_units
    vertical_base_units

Each of the attributes is required in the sense that omitting any of them produces this error message:

    AT--001: Required attribute not found.

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

The attributes **driver\_name**, **output\_name** and **output\_suffix** are all copied into the binary file as character strings. The last four attributes are converted to unsigned integers.

The attributes **driver\_name**, **output\_name** and **output\_suffix** can be given as empty strings and gendev will encode them as such in the binary file.

The attributes **output\_name** and **output\_suffix**, together with the value, if any, given by command-line option OUTPUT, and the name of the document specification given on the command-line, determine the name of the output file. These appear to be the rules:

-   If the command-line option OUTPUT was used and it's value:
    -   has a file name and an extension, it is used, including any path;
    -   has the form "\*.ext", the extension is used but the file name is taken from the name of the document specification, and any path given is prefixed to the file name; or
    -   has a name but no extension, the value of the attribute **output\_suffix** is used for the extension, and any path given is prefixed to the file name; or
    -   has a path but no file name and no extension, the value of the attribute **output\_suffix** is used for the extension, and any path given is prefixed to the file name, which is taken from the name of the document specification.
-   if the command-line option OUTPUT was not used, then the value of the attribute **output\_name** is used in this way:
    -   if it consists entirely of a path, the character "\*", or both, or is an empty string, it is ignored and the file name is taken from the name of the document specification; or
    -   if it is a character string, that string is used for the file name, including any path.
-   if the command-line option OUTPUT was not used or did not include an extension, then the value of the attribute **output\_suffix** is used in this way:
    -   if it is a character string, that string is used for the extension; or
    -   if it is an empty string, then the output file will have no extension.

The term "path" must be understood to include any disk partition letter plus ":" or any directory path, relative or absolute, or both together (in which case the disk partition letter and ":" come first and the path is not relative).

Testing confirms that, under certain conditions, wgml 4.0 will direct its output to a system device (in particular, LPT1):

-   the value of attribute **output\_name** is a device name; or
-   the value used with command-line option OUTPUT is a device name.

The [WGML 4 Reference](WGML-References#reference1) implies that the value of attribute **output\_suffix** must be an empty string for this to happen, but limited testing suggests that it depends on what the operating system will accept: if the device name plus extension is acceptable as a device name, the output goes to a device; if not, it goes to a file. If certainty is desired, then the value of attribute **output\_suffix** should be an empty string. Also, it is probably not a good idea to use a device name as a file name, even if an extension is provided as well.

The numerical attributes all have a minimum value of "0". Negative values are not allowed, producing this error message:

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

The maximum value of the numerical attributes depends on the version of gendev. Both versions both produce this error message when the value is too large:

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

but do so under different conditions:

-   gendev 3.33 produces it if the value of a numeric attribute exceeds $CCCF.
-   gendev 4.1 produces it if the value of a numeric attribute exceeds $7FFFFFFF.

This is the only difference between the version 3.33 gendev and the version 4.1 gendev which affects the source file with respect to the Attributes.

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

    Attributes {
        uint8_t  driver_name_length;
        uint8_t  driver_name[driver_name_length];
        uint8_t  output_name_length;
        uint8_t  output_name[output_name_length];
        uint8_t  output_extension_length;
        uint8_t  output_extension[output_extension_length];
        PageData pagedata;
    };

If any of the attributes **driver\_name**, **output\_name** and **output\_suffix** appear in the binary file as an empty string, then that empty string is parsed as a NULL pointer.

For version 3.33 files, the PageData structure is:

    PageData {
        uint16_t designator = 0x1200;
        uint16_t page_width;
        uint16_t page_depth;
        uint16_t horizontal_base_units;
        uint16_t vertical_base_units;
    };

For version 4.1 files, the PageData structure is:

    PageData {
        uint16_t designator = 0x2200;
        uint32_t page_width;
        uint32_t page_depth;
        uint32_t horizontal_base_units;
        uint32_t vertical_base_units;
    };

The designators are used to determine which structure is present in the binary file in the research code, and to ensure that a version 4.1 file is being processed in the binary device file [subsystem](WGML#The-Binary-Device-File-Subsytem) of wgml.

The :BOX Block
--------------

The :BOX block was changed from that shown in [WGML 4 Reference](WGML-References#reference1) by the README file produceable from the [WGML 3.33 Update](WGML-References#reference2). The current source file format is:

    :BOX
       font
       horizontal_line
       vertical_line
       top_left
       top_right
       bottom_left
       bottom_right
       top_join
       bottom_join
       left_join
       right_join
       inside_join
    :eBOX.

All of the attributes are required.

The attribute **font** can take two forms:

-   a number (which does *not* have to be found in a :DEFAULTFONT block); or
-   a string containing a font name.

If it is a string, then these restrictions apply:

-   it must also be found in a :DEVICEFONT block; and
-   it cannot be an empty string or this error results:

<!-- -->

    SN--019: Fontname not specified in :devicefont

The values of the other attributes are the characters to use for the indicated purpose.

The corresponding struct in the binary file is:

    BoxBlock {
        FontAttribute fontattribute;
        uint8_t       count = 0x0f;
        uint8_t       horizontal_line;
        uint8_t       vertical_line;
        uint8_t       top_left;
        uint8_t       top_right;
        uint8_t       bottom_left;
        uint8_t       bottom_right;
        uint8_t       top_join;
        uint8_t       bottom_join;
        uint8_t       left_join;
        uint8_t       right_join;
        uint8_t       inside_join;
        uint8_t       buffer[4] = { 0x00, 0x00, 0x00, 0x00 };
    };

The field **fontattribute** is a [FontAttribute](#The-FontAttribute-Structure) struct. Because an empty string is not accepted by gendev, if the field **FontAttribute.designator** indicates that the font was provided as a string, then a zero-length string is treated by the binary device file [subsystem](WGML#The-Binary-Device-File-Subsytem) of wgml as a format error.

The interpretation of the field **count** as a count and of the field **buffer** as part of the BoxBlock are codependent and may or may not be correct; there is no way to tell.

The remaining fields contain the character specified in the corresponding attribute.

The :DEFAULTFONT Block
----------------------

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

    :DEFAULTFONT
       font
       fontname
       font_height
       font_space
       fontstyle
    :eDEFAULTFONT.

The attributes **font**, **fontname**, and **fontstyle** are required. The attribute **font\_space** is required if the attribute **font\_height** is present. The attribute **font\_height** is never required.

The value of the attribute **font** is an 8-bit unsigned integer. Taken as a group, these values have these characteristics:

-   Each value can occur only once.
-   The values do not have to be sequential (gaps are allowed).
-   The values may be used in any order.

As will be seen from the discussion of the resulting binary file, gaps in the values of the attribute **font** waste space in the file, and so these values should be both small and gapless unless there is a good reason to do otherwise.

For version 4.1 of gendev, there is no detectable upper limit on the value of the attribute **font**. For version 3.33 of gendev, an upper limit of "$ff" is enforced with this message:

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

When these values are used in other blocks to designate fonts, they are never encoded in more than one byte.

The value of the attribute **fontname** must match the value of the attribute **fontname** of a :DEVICEFONT block in the same source file. An empty string will not be accepted by gendev, producing this error message:

    AT--002: Missing attribute value

If the attribute **font\_height** is provided but the attribute **font\_space** is not, this error results:

    SN--080: The font_space attribute must be specified
             if the font_height attribute is present

The attribute **font\_space** can be provided without requiring the attribute **font\_height** to be present.

The attributes **font\_height** and **font\_space** are entered in points, of which there are 72 to the inch. They must be in decimal: prefixing them with **$** produces this error message:

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

even for $1, which is certainly not too large! These attributes are limited to the range \[0..72\], that is, the attributes can specify a value no larger than 1 inch or the same error message results.

The value of the attribute **fontstyle** is a character string. It does not have to be unique; the same value can be used with more than one :DEFAULTFONT block. It is not restricted to the set of "keyword values" given in [WGML 4 Reference](WGML-References#reference1): any string may be used, so long as it does not contain embedded spaces. A string with embedded spaces produces this error message:

    SN--094: Font style name may not contain spaces

An empty string is accepted by gendev, provided the delimiters are present. An empty string without delimiters produces this error:

    AT--002: Missing attribute value

See [wgml Fonts](WGML-Fonts) for a fuller discussion of Font Styles.

The corresponding struct in the binary file is:

    DefaultfontBlock {
        uint8_t     count = 0x02;
        uint16_t    font_count;
        DefaultFont fonts[count];
    };

The field **count** appears to contain the number of bytes occupied by the field **font\_count**.

The value of the field **font\_count** is the highest value found for the attribute **font** in any of the :DEVICEFONT blocks plus 1. The DefaultFont structs are enumerated from "0" to the value of this field minus 1 since a :DEFAULTFONT block with the value of "0" for the attribute **font** is required to be present in the source file.

When encoded by the version 3.33 gendev, the highest value of the attribute **font** allowed is $ff, and the field **font\_count** then contains "0x0100".

When encoded by the version 4.1 gendev, the field **font\_count** can contain all values from "0x0000" (indicating a "highest value" of "$ffff") to "0xffff". Larger values wrap to show only the lower 16 bits, yet produce the indicated number of entries; this was tested with several large values. The value 0x100000000 was accepted by gendev 4.1 but I did not have time to see if gendev 4.1 would actually produce a binary file or if it had hung.

Values higher than $ff cannot be used (encoded) in a [FontAttribute](#The-FontAttribute-Structure) struct. It is possible that they are not useable, although an exploration of how the related tags are treated by wgml will be needed to settle this point definitively.

The field **fonts** is an array of structs encoding :DEFAULTFONT blocks. The values of the attribute **font** found in those :DEFAULTFONT blocks are not encoded in the binary file but serve as indexes to the valid entries in this array. Since the values of the attribute **font** can include gaps, some of these entries may have values indicating a nonexistent :DEFAULTFONT block.

The DefaultFont struct for an existing :DEFAULTFONT block is:

    DefaultFont {
        uint8_t  font_style_length;
        uint8_t  font_style[font_style_length];
        uint8_t  count = 0x04;
        uint16_t font_height;
        uint16_t font_space;
        uint8_t  font_name_length;
        uint8_t  font_name[font_name_length];
    };

The fields **font\_style\_length** and **font\_style** together encode the character string given as the value of attribute **fontstyle**. An empty string is parsed as a NULL pointer.

The field **count** records the number of bytes occupied by the fields **font\_height** and **font\_space**.

The values for the fields **font\_height** and **font\_space** are unsigned integers representing the values of the corresponding attributes in hundredths of a point. These details should be noted:

-   To be clear, this means that, if the attribute **font\_height** has the value "12", then the field **font\_height** will have the value "1200".
-   This suggests that these are the values which the **%font\_height()** and **%font\_space()** functions return, at least initially.
-   The documentation of these functions shows such values as "1225", which cannot occur in the binary file because the values of the attributes must be integers. Thus, it is possible that the values returned by the functions are subject to additional manipulation.
-   If they are omitted, then the effect is the same as if the value of the attribute was "0": "0x0000" is placed in the binary file.

The fields **font\_name\_length** and **font\_name** together encode the character string given as the value of attribute **fontname**.

The DefaultFont entry for a nonexistent :DEFAULTFONT block has these values (with my interpretations of them, given the above struct):

    01 00 (the fontstyle_length & fontstyle)
    04 00 00 00 00 (the count, font_height & font_space)
    01 00 (the fontname_length & fontname)

This form of DefaultFont has two instances illustrating how an empty string appears in the binary file format. This also shows that, even though gendev will not allow an empty string for attribute **fontname** in the source file, an empty string can nonetheless appear in the binary file. Because it is not possible to distinguish between a one-character string value and an empty string before acquiring the data, both will be parsed as empty strings, not as NULL pointers.

This implies that wgml must either access the DefaultFont instances in a way that guarantees it is always accessing a valid instance or be prepared to treat a NULL pointer for the font name as indicating that the instance corresponds to a nonexistent :DEFAULTFONT block.

The :DEVICEFONT Block
---------------------

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

    :DEVICEFONT
       fontname
       fontswitch
       fontpause
       resident
    :eDEVICEFONT.

All of the attributes are required, at least in the sense of being present in the :DEVICEFONT block.

The attribute **fontname** is a character string giving the defined name of the font: if the font is ever used, wgml will expect to be able to use this name to find the binary file encoding the corresponding :FONT block. If an empty string is used for the value of this attribute, gendev produces this error message:

    SN--006: Fontname is too long or is an empty string

The attribute **fontswitch** is a character string giving the name of the [:FONTSWITCH](WGML-Driver-File-Blocks#The-FONTSWITCH-Block) block to use with this font. Since this block is located in a binary driver file, gendev cannot guarantee that it exists. An empty string can be used as the value of this attribute if there is no :FONTSWITCH block associated with this font.

The attribute **fontpause** is a character string giving the name of the [:FONTPAUSE](#The-FONTPAUSE-Block) block to use with this font. Since this block is located in the same binary device file, gendev will produce this error message if it is not found:

    SN--022: The fontpause in :devicefont has no match in :fontpause.

An empty string can be used as the value of this attribute if there is no :FONTPAUSE block associated with this font.

The attribute **resident** can take one of two values: YES and NO. Using any other value provokes this response:

    AT--003: Invalid attribute value

The corresponding struct in the binary file is:

    DevicefontBlock {
        uint8_t    count = 0x02;
        uint16_t   font_count;
        DeviceFont fonts[devicefont_count];
    };

The field **count** contains the number of bytes occupied by the field **devicefont\_count**.

The field **font\_count** contains the number of :DEVICEFONT blocks encoded.

The field **fonts** is a array of DeviceFont structs, each of encodes a single :DEVICEFONT block. The array is ordered alphanumerically by the values of the attribute **fontname** which, considering the HP :DEVICE blocks with 225 :DEVICEFONT blocks, presumably helps speed up searching through the array.

The DeviceFont struct is:

    DeviceFont {
        uint8_t    font_name_length;
        uint8_t    font_name[font_name_length];
        uint8_t    font_switch_length;
        uint8_t    font_switch[font_switch_length];
        uint8_t    nulls[2] = { 0x00, 0x00 };
        uint8_t    count = 0x03;
        uint8_t    resident = < 0x00 | 0x01 >;
        uint16_t   font_pause;
    };

The fields **font\_name\_length** and **font\_name** together encode the character string given as the value of attribute **fontname**. gendev should never encode an empty string for this field; if one is found, it is parsed as a format error.

The fields **font\_switch\_length** and **font\_switch** together encode the character string given as the value of attribute **fontswitch**. If an empty string is found, then it is parsed as a NULL pointer.

The field **nulls** serves no known purpose.

The field **count** contains the number of bytes occupied by the fields **resident** and **font\_pause**.

The field **resident** contains one of two values:

-   If the value of the attribute **resident** is "no", then the value in the field **resident** will be "0x00".
-   If the value of the attribute **resident** is "yes", then the value in the field **resident** will be "0x01".

The value of the field **font\_pause** requires some explanation. It is the sum of all values of the fields **functions.codeblocks\[\].count** of the DeviceFile struct up to the CodeBlock encoding the :FONTPAUSE block specified by the :DEVICEFONT block. This is not a straightforward offset from a fixed point because it ignores several fields found in each CodeBlock. It will roll over if this value is larger than 0xffff, which could make it ambiguous if, for example, both 0x0531 and 0x10531 happen to be valid given the sizes of the CodeBlocks. If there is no corresponding :FONTPAUSE, that is, if an empty string was entered as the value of the corresponding attribute, then the value "0xFFFF" is used for the field **font\_pause**.

The FontAttribute Structure
---------------------------

The FontAttribute struct is used by these blocks to encode the value given for attribute **font**:

1.  The :BOX block.
2.  The :UNDERSCORE block.

The treatment of an empty string entered as the value of attribute **font** depends on which block it occurs in and so is discussed in those sections.

The format for the FontAttribute depends on how it is given in the source file.

When a number is used to designate the font the corresponding struct in the binary file is:

    FontAttribute {
        uint16_t designator = 0x0101;
        uint8_t  count = 0x01;
        uint8_t  font_number;
    };

The field **designator** is always "0x0101" if the font was designated by a number.

The field **count** is always "0x01", the number of bytes occupied by the field **font\_number**.

The field **font\_number** contains the value of the attribute **font** in the block being encoded.

When a character string is used to designate the font the corresponding struct in the binary file is:

    FontAttribute {
        uint16_t designator = 0x0201;
        uint8_t  font_name_length;
        uint8_t  font_name[font_length];
    };

The field **designator** is always "0x0201" if the font was designated by a character string.

The fields **font\_name\_length** and **font\_name** together encode the character string given as the value of attribute **font**.

The field **designator** can be used to tell which version of FontAttribute is present in the binary file.

The :FONTPAUSE Block
--------------------

Since no :FONTPAUSE blocks occur in any of the available source files, I cannot say that the description of the :FONTPAUSE block given in [WGML 4 Reference](WGML-References#reference1) is still correct (it is possible that the block actually has additional new features), but I can say that the description works:

    :FONTPAUSE
       type = ’character string’
       :value.
          <device functions>
       :evalue.
    :eFONTPAUSE.

The attribute is required. If an empty string is used, then gendev produces this error message:

    SN--008: Type cannot be an empty string in :fontpause

This value never appears in the binary file, so it is never parsed.

The value of the attribute **type** must be found as the value of the attribute **fontpause** of a :DEVICEFONT block in the same source file. It must also be unique: duplication produces this error:

    SN--020: Duplicate :fontpause type

The :VALUE block is required; if it is missing, this error results:

    SN--040: Expecting :value tag

The :FONTPAUSE block is the only block in the :DEVICE block which does not have its own structure in the binary file. The :VALUE block is encoded in the in the field **functions.codeblocks** of the DeviceFile struct and the **devicefont.devicefonts\[\].fontpause** field for the corresponding :DEVICEFONT block is used to access the resulting CodeBlock.

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 PagegeometryBlock Struct
----------------------------

The Pagegeometry Struct encodes the :PAGESTART and :PAGEOFFSET blocks.

The struct in the binary file for version 3.33 is:

    PagegeometryBlock {
        uint16_t x_start;
        uint16_t y_start;
        uint16_t x_offset;
        uint16_t y_offset;
    };

The struct in the binary file for version 4.1 is:

    PagegeometryBlock {
        uint32_t x_start;
        uint32_t y_start;
        uint32_t x_offset;
        uint32_t y_offset;
    };

The type of block, that is, the size of the fields, is the same as the size used for the numeric Attributes and so the field **designator** of PageData applies to these values as well.

The fields **x\_start** and **y\_start** encode the attributes **x\_start** and **y\_start** (respectively) of the :PAGESTART Block, if it is present. If the :PAGESTART Block is not present, their value is "0x0000" or "0x00000000" (depending on the number of bits used).

The fields **x\_offset** and **y\_offset** encode the attributes **x\_start** and **y\_start** (respectively) of the :PAGEOFFSET Block, if it is present. If the :PAGEOFFSET Block is not present, their value is "0x0000" or "0x00000000" (depending on the number of bits used).

The :PAGEOFFSET Block
---------------------

This block is not documented in either [WGML 4 Reference](WGML-References#reference1) or in the README file produceable from the [WGML 3.33 Update](WGML-References#reference2). An error message, SN--079, referencing a missing :ePAGEOFFSET tag, is the only documentation other than :CMT. lines in the existing source files.

This is the format shown in :DEVICE blocks where it is used:

    :PAGEOFFSET
       x_start
       y_start
    :ePAGEOFFSET.

The attributes are both required. They are numeric values which are converted to unsigned integers.

The attributes both have a minimum value of "0". Negative values are not allowed, producing this error message:

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

The maximum value of the attributes depends on the version of gendev. Both versions both produce this error message when the value is too large:

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

but do so under different conditions:

-   gendev 3.33 produces it if the value of a numeric attribute exceeds $CCCF.
-   gendev 4.1 produces it if the value of a numeric attribute exceeds $7FFFFFFF.

This is the only difference between the version 3.33 gendev and the version 4.1 gendev which affects the source file with respect to the :PAGEOFFSET block.

The attribute **x\_start** is placed in the PagegeometryBlock as the field **x\_offset**. The attribute **y\_start** is placed in the PagegeometryBlock as the field **y\_offset**.

This block is preceeded by this comment where it is used:

    :CMT. Position past the unprintable region of the page

which, as noted above, is the only documentation available.

[Page Layout Subsystem](WGML-Page-Layout-Subsystem) discusses this block in a larger context.

The :PAGESTART Block
--------------------

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

    :PAGESTART
       x_start
       y_start
    :ePAGESTART.

The attributes are both required. They are numeric values which are converted to unsigned integers.

The attributes both have a minimum value of "0". Negative values are not allowed, producing this error message:

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

The maximum value of the attributes depends on the version of gendev. Both versions both produce this error message when the value is too large:

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

but do so under different conditions:

-   gendev 3.33 produces it if the value of a numeric attribute exceeds $CCCF.
-   gendev 4.1 produces it if the value of a numeric attribute exceeds $7FFFFFFF.

This is the only difference between the version 3.33 gendev and the version 4.1 gendev which affects the source file with respect to the :PAGESTART block.

The attribute **x\_start** is placed in the PagegeometryBlock as the field **x\_start**. The attribute **y\_start** is placed in the PagegeometryBlock as the field **y\_start**.

[Page Layout Subsystem](WGML-Page-Layout-Subsystem) discusses this block in a larger context.

The :PAUSE Block
----------------

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

    :PAUSE
       place
       :value.
          <device functions>
       :evalue.
    :ePAUSE.

The attribute **place** is required. It takes a character string selected from these key values:

-   START
-   DOCUMENT
-   DOCUMENT\_PAGE
-   DEVICE\_PAGE

Use of any other value produces this error message:

    AT--003: Invalid attribute value

The :PAUSE blocks for the various values of the attribute **place** can occur in any order. The resulting CodeBocks are placed in the FunctionsBlock in the order encountered in the source file. They are all placed before any CodeBlocks resulting from any :FONTPAUSE blocks.

The :VALUE block is required: if it is missing, then this error message is produced:

    SN--040: Expecting :value tag

The corresponding struct in the binary file is:

    PauseBlock {
        uint8_t  start_pause_count = 0x02;
        uint16_t start_pause;
        uint8_t  document_pause_count = 0x02;
        uint16_t document_pause;
        uint8_t  docpage_pause_count = 0x02;
        uint16_t docpage_pause;
        uint8_t  devpage_pause_count = 0x02;
        uint16_t devpage_pause;
    };

The fields **start\_pause\_count**, **document\_pause\_count**, **docpage\_pause\_count** and **devpage\_pause\_count** each contain "0x02", the number of bytes occupied by the following field.

The values of the **start\_pause**, **document\_pause**, **docpage\_pause** and **devpage\_pause** fields require some explanation. They are the sum of all values of the fields **functions.codeblocks\[\].count** of the DeviceFile struct up to the CodeBlock encoding the :PAUSE block indicated by the field name. This is not a straightforward offset from a fixed point because it ignores several fields found in each CodeBlock. It will roll over if this value is larger than 0xffff, which could make it ambiguous if, for example, both 0x0531 and 0x10531 happen to be valid given the sizes of the CodeBlocks. If there is no corresponding :PAUSE block, then the value "0xFFFF" is used for the corresponding field.

If no :PAUSE blocks exist in the source file, then the PauseBlock will be:

    02 FF FF 02 FF FF 02 FF FF 02 FF FF

The TranslationBlock 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.

This block has four different forms for four different situations:

1.  Neither an IntransBlock nor an OuttransBlock is present.
2.  An IntransBlock is present, but an OuttransBlock is not.
3.  An OuttransBlock is present, but an IntransBlock is not.
4.  Both an IntransBlock and an OuttransBlock are present.

When neither an IntransBlock nor an OuttransBlock is present, the struct in the binary file is:

    TranslationBlock {
        uint8_t count         = 0x03;
        uint8_t data_count    = 0x00;
        uint8_t outtrans_flag = 0x00;
        uint8_t intrans_flag  = 0x00;
    };

These fields appear in all TranslationBlock variants.

The value of the field **count** is always "0x03", the number of bytes occupied by the next three fields.

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 there is a 1-byte OuttransBlock present, the value will be "0x00".

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

-   the value "0x00" indicates that no OuttransBlock is 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 no IntransBlock is present; and
-   the value "0x01" indicates that an IntransBlock is present.

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

    TranslationBlock {
        uint8_t      count         = 0x03;
        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, the struct in the binary file will be:

    TranslationBlock {
        uint8_t       count         = 0x03;
        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 both an IntransBlock and an OuttransBlock are present, the struct in the binary file will be:

    TranslationBlock {
        uint8_t       count         = 0x03;
        uint8_t       data_count;
        uint8_t       outtrans_flag;
        uint8_t       intrans_flag  = 0x01;
        IntransBlock  intrans;
        OuttransBlock outtrans;
    };

An IntransBlock contains 0x102 bytes. An OuttransBlock contains either 0x102 bytes (if the value of the field **outtrans\_flag** is 0x01) or 0x202 bytes (if the value of the field **outtrans\_flag** is 0x02) plus the value of field **data\_count** bytes. Thus, every form of TranslationBlock allows computation of the number of bytes in that TranslationBlock.

The :UNDERSCORE Block
---------------------

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

    :UNDERSCORE
       font
       score_value
    :eUNDERSCORE.

Both attributes are required.

The value of the attribute **font** can be a number or a character string. If it is a number, it does not have to correspond to any of the :DEFAULTFONT blocks. If it is a character string, a :DEVICEFONT block must exist naming the same font, unless the string is empty (see discussion below).

If the attribute **score\_value** contains no character or more than one character, then this error results:

    AT--007: The attribute value cannot have more than one character

The UnderscoreBlock has this format:

    UnderscoreBlock {
        FontAttribute font;
        uint8_t       count = 0x05;
        uint8_t       underscore_char;
        uint8_t       buffer[4] = { 0x00, 0x00, 0x00, 0x00 };
    }

The field **font** is a [FontAttribute](#The-FontAttribute-Structure) struct.

The interpretation of the fields **count** as a count and **buffer** as part of the UnderscoreBlock are codependent and may or may not be correct; there is no way to tell.

The field **underscore\_char** contains the value of the attribute **score\_value**.

If no :UNDERSCORE block exists in the source file, the binary file will contain:

    01 02 00 05 5f 00 00 00 00

which is:

-   a FontAttribute block with the "character string" designator and a length byte of "0x00" with no font name;
-   the field **count** with its usual value;
-   the field **underscore\_char** with value "0x5f" (**\_**); and
-   the four nulls.

This is consistent with the [WGML 4 Reference](WGML-References#reference1), which documents the use of "\_" if the block is omitted.

Interestingly, if an empty string is provided for the value of attribute **font**, the same pattern occurs (provided, of course, that "\_" is specified as the value of attribute **underscore\_char**). This suggests the possibility that, if no font is specified for the underscore character, then whatever font is currently in use is used. There are statements in the [WGML 4 Reference](WGML-References#reference1) which support this possibility without explicitly confirming it. Unfortunately, those statements appear to be referring to the pre-3.33 version of wgml, not to version 4.0.

Preliminary testing revealed this interesting facts:

-   Neither "uscore" nor "underscore" is treated by wgml as a built-in font style: if they are to be used, they must be defined in a :FONTSTYLE block. This is probably why :FONTSTYLE blocks exist for "uscore" and "uline" rather than "underscore" and "underline": the former are used with the FONT command-line option, and now they must match a :FONTSTYLE block, while the latter are shown only with :DEFAULTFONT blocks in the manual.
-   The word to be underscored is not printed automatically. Removing the :STARTVALUE block that generates a CodeBlock of type "0x05" does not cause the text to be printed; thus, whatever the value "0x101" discussed [here](WGML-Device-Function-Notes#Provisional-Conclusions) may signify to wgml, it does *not* tell wgml to print the text itself. Removing all interior blocks, that is, reducing the style definition to just the style name, does cause the text to appear -- but it is not underscored. Indeed, there is no indication that any CodeBlocks are executed before or after the emphasized text as such at all (the text in which it is embedded does, of course, show the execution of appropriate CodeBlocks). Part of the investigation of the [Device Function Language](WGML-Device-Function-Language) will involve determining more precisely when and how text is actually printed.
-   All of the CodeBlocks from the :FONTSTYLE block appear to be done before the text would be printed (a blank space is seen in the output). It is not clear how this actually works.
-   Extensive testing of situations where different fonts were and were not specified by the :UNDERSCORE block and the :DEFAULTFONT block involved (easily identifiable if it is the only :DEFAULTFONT block that uses the font style "underscore") showed no indication that the :FONTSWITCH block CodeBlocks are invoked under any (tested) conditions whatsoever. This included using an empty string or a number for the value of attribute **font** in the :UNDERSCORE block as well as specifying a different font name.
-   However, when the device functions %ulineon() and %unlineoff() were being tested for categorization, a :LINEPROC with %ulineon() in the :STARTVALUE and %ulineoff() in the :ENDVALUE not only resulted in underscores being inserted into the file but also showed the font changing. So, wgml will need to distinguish between an empty string and a numerical value for attribute **font**.
