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

- [The Attributes](#the-attributes)
- [The :ABSOLUTEADDRESS Block](#the-absoluteaddress-block)
- [The :DBOX Block](#the-dbox-block)
- [The Device Function Flags](#the-device-function-flags)
- [The :FINISH Block](#the-finish-block)
- [The :FONTSTYLE Block](#the-fontstyle-block)
- [The :FONTSWITCH Block](#the-fontswitch-block)
- [The :HLINE Block](#the-hline-block)
- [The :HTAB Block](#the-htab-block)
- [The :INIT Block](#the-init-block)
- [The :NEWLINE Block](#the-newline-block)
- [The :NEWPAGE Block](#the-newpage-block)
- [The :PAGEADDRESS Block](#the-pageaddress-block)
- [The ThicknessBlock](#the-thicknessblock)
- [The :VLINE Block](#the-vline-block)
</details>

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

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

    defined_name
    member_name
    rec_spec
    fill_char

Each of the attributes is required. 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 attribute **rec\_spec** is copied into the binary file as a character string. It is supposed to have a specific format, but gendev does not enforce this: any string can be entered, including an empty string. Testing clearly showed that an empty string has the same result as "(t:132)", which is the documented default value for a source file. Limited testing with values not matching the specified format suggests that "(t:132)" is used in those cases as well.

The attribute **fill\_char** is copied into the binary file as a single character. If it is an empty string, or a string with more than one character, this error message results:

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

The corresponding struct in the binary file is:

    Attributes {
        uint8_t  rec_spec_length;
        uint8_t  rec_spec[rec_spec_length];
        uint8_t  unknown = {0x04};
        uint8_t  fill_char;
    };

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

The field **unknown** originally appeared to be a "count" field (as discussed in [&quot;Count&quot; Fields](WGML-Meta-Data#Count-Fields)) of the lengths of the field **fill\_char** and the following three bytes; however, the first two of those three bytes turned out to encode the :PAGEADDRESS block, and so all three of them have now been assigned to PageaddressBlock, leaving field **unknown** a complete mystery.

The field **fill\_char** contains the value of the attribute **fill\_char**.

The :ABSOLUTEADDRESS Block
--------------------------

The description in [WGML 4 Reference](WGML-References#reference1) appears to still be correct:

    :ABSOLUTEADDRESS
       :value.
          <device functions>
       :evalue.
    :eABSOLUTEADDRESS.

The :VALUE block is required: if omitted, this error message results:

    SN--055: Expecting :value tag

Only one :VALUE block is allowed; a second :VALUE block provokes this error message:

    SN--065: Expecting :eabsoluteaddress tag

The :ABSOLUTEADDRESS block is encoded in a Variant A FunctionsBlock. If the :ABSOLUTEADDRESS block is present in the source file then, since exactly one :VALUE block is required to be present inside it, there will be exactly one CodeBlock and field **count** of the FunctionsBlock will have the value "0x0001".

If no :ABSOLUTEADDRESS block is present in the source file, then the field **count** of the FunctionsBlock will have the value "0x0000".

The :DBOX Block
---------------

This appears to be exactly as described in [WGML 4 Reference](WGML-References#reference1):

    :DBOX
       thickness
       :value.
          <device functions>
       :evalue.
    :eDBOX.

This block is not required.

If the :DBOX block is present, then the attribute **thickness** is required. If it is not present, or is not placed before the :VALUE block, this error message results:

    AT--001: Required attribute not found

If the :DBOX block is present, then the :VALUE block is required: if no :VALUE block is present, this error message results:

    SN--055: Expecting :value tag

Only one :VALUE block is allowed: if more than one exists, this error message appears with the number of the line on which the second :VALUE tag is located:

    SN--074: Expecting :edbox tag

The corresponding struct in the binary file is:

    DboxBlock {
     FunctionsBlock functions;
     ThicknessBlock thickness;
    }

The field **functions** is a [Variant A FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-A).

If the :DBOX block is present in the source file then, since exactly one :VALUE block is required to be present inside it, there will be exactly one CodeBlock and field **functions.count** will have the value "0x0001".

The field **thickness** is a [ThicknessBlock](#The-ThicknessBlock).

If no :DBOX block is present in the source file, then the field **functions.count** will have the value "0x0000" and there will be no [ThicknessBlock](#The-ThicknessBlock) at all -- all that will be left are the [final nulls](WGML-COP-Files#Padding).

The Device Function Flags
-------------------------

The [:FONTSTYLE](#The-FONTSTYLE-Block) and [:FONTSWITCH](#The-FONTSWITCH-Block) blocks, when encoded by gendev, include a 21-byte array which, initially, appeared to be composed entirely of nulls, but upon closer examination turned out to consist of 21 flags, each indicating the presence or absence of a specific device function in the enclosed :STARTVALUE block (only).

Testing has confirmed that flags do not exist for these functions in any other context; specifically:

-   not the :ENDVALUE block of a :FONTSTYLE or :FONTSWITCH block; \*for :FONTSTYLE, not any of the :STARTVALUE blocks (or any other block) found in any of the :LINEPROC blocks;
-   not in any other block in a :DRIVER block; and
-   not in any block in a :DEVICE file.

This table lists the flags by offset and corresponding device function:

    Flag   Function
    00     %wgml_header()
    01     %font_outname1()
    02     %font_outname2()
    03     %font_resident()
    04     %time()
    05     %date()
    06     %default_width()
    07     %font_number()
    08     %tab_width()
    09     %page_depth()
    10     %page_width()
    11     %x_address()
    12     %y_address()
    13     %x_size()
    14     %y_size()
    15     %thickness()
    16     %font_height()
    17     %font_space()
    18     %line_height()
    19     %line_space()
    20     %pages()

These flags are not included in the cop\_driver struct provided by the binary device file [subsystem](#The-FONTSTYLE-Block) because they have no obvious utility. Identifying them will allow our gendev to produce them (if necessary) for use with wgml 4.0 and our wgml to use them (once the cop\_driver struct is modified to include them) if that turns out to be necessary for our wgml to reproduce the results of wgml 4.0.

It should be kept in mind that some of these functions (in particular, %font\_outname1()) occur in other contexts (such as the :FONTVALUE block in an :INIT block) without any flag to record its presence, and are processed correctly by wgml 4.0 every time a PostScript or Acrobat version of an Open Watcom document is produced. Thus, the flags are *not* always required for wgml to process the corresponding device function.

The :FINISH Block
-----------------

The description in [WGML 4 Reference](WGML-References#reference1) appears to still be correct:

    :FINISH
       place
       :value.
          <device functions>
       :evalue.
    :eFINISH.

The :FINISH block is not required.

If a :FINISH block is present, then the attribute **place** is required. It takes a character string selected from these key values:

-   END
-   DOCUMENT

If a :FINISH block is present, then at least one :VALUE block must be present; if only the attribute **place** is present, this error meesage occurs:

    SN--055: Expecting :value tag

Any number of :VALUE blocks may be present, so long as the attribute **place** preceeds all of them. Each such block will become a CodeBlock; however, as noted below, only the first is actually used by wgml.

The corresponding struct in the binary file is:

    FinishFuncs {
        uint16_t       count;
        FinishBlock    finishblock[count];
    }

This is a [Variant C FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-C).

If either a :FINISH block with the value END for the attribute **place** or a :FINISH block with the value DOCUMENT for the attribute **place** (but not both) is present in the source file then the field **count** will have the value "0x0001".

If both :FINISH blocks are present in the source file then the field **count** will have the value "0x0002". Note that there can be, at most, two :FINISH blocks, one for each value of the attribute **place**.

The struct FinishBlock is:

    FinishBlock {
        uint8_t        designator;
        uint16_t       count;
        CodeBlock      codeblock[count];
    };

The value of the field **designator** depends on the value of the attribute **place**: it is "0x01" for END and "0x02" for DOCUMENT.

The value of the field **count** is the number of CodeBlocks contained in this FinishBlock. Since multiple :VALUE blocks are allowed in an :FINISH block, and since each :VALUE block becomes a CodeBlock, this value is limited only by being a single byte. The CodeBlocks will appear in the order that the :VALUE blocks appeared in the source file.

If there are two :FINISH blocks, then in the binary file, the FinishBlock encoding the :FINISH block with the value END for the attribute **place** will always be found first, even if the :FINISH block with the value DOCUMENT for the attribute **place** comes first in the source file.

If no :FINISH block is present in the source file, then the field **count** of FinishFuncs will have the value "0x0000".

The test device/driver files produced two results:

1.  The :FINISH block with the value DOCUMENT for the attribute **place** was only used if the :FINISH block with the value END for the attribute **place** was not present.
2.  In either case, while multiple :VALUE blocks are allowed in the source and encoded in the binary file, only the *first* CodeBlock is actually invoked.

No available :FINISH block has more than one :VALUE block. All :DRIVER blocks have a :FINISH block which, at a minimum, does a %recordbreak(). Those :VALUE blocks consisting entirely of %recordbreak() are usually documented to force the last line to the output device, *i.e.*, to flush the output buffer. Those :VALUE blocks which contain additional functions usually mention forcing the last line and/or the last control codes in the accompanying documentation.

The :FONTSTYLE Block
--------------------

The :FONTSTYLE block, as such, is not documented.

In [WGML 4 Reference](WGML-References#reference1) there are two error messages (SN-084 and SN-088) referencing :FONTSTYLE. In the READ ME file produceable from the [WGML 3.33 Update](WGML-References#reference2) there is a note "\[c\]hanges to device driver source with the addition of new control structures called :FONTSTYLE and the removal of :BOLDEND, :BOLDSTART, :UNDERSTART and :UNDEREND". The replaced blocks are documented, but consist entirely of a :VALUE block, and so this is not very helpful.

The :DRIVER blocks found in the .PCD files available show this structure:

    :FONTSTYLE
      type
      :startvalue
         <device functions>
      :estartvalue.
      :lineproc
         pass
         :startvalue
            <device functions>
         :estartvalue.
         :firstword
            <device functions>
         :efirstword.
         :startword
            <device functions>
         :estartword.
         :endword
            <device functions>
         :eendword.
         :endvalue
            <device functions>
         :eendvalue.
      :elineproc.
      :endvalue
         <device functions>
      :eendvalue.
    :eFONTSTYLE.

If any block shown above as containing device functions is empty, then gendev 4.1 produces this message:

    SN--034: Expecting text before termination tag.

and source file processing stops.

The files investigated contain copious :CMT. lines -- except for the :FONTSTYLE blocks. Even the lines found in HELPDRV.PCD cannot be trusted, as they appear to have been copied from TASADRV.PCD. Thus, no documentation exists for this block at all, apart from examination of the existing examples and the device functions they invoke.

The attribute **type** is required; however, an empty string is accepted by both gendev 4.1 and wgml 4.0.

The value of the attribute **type**, when not an empty string, is a string with these properties:

-   If the string contains spaces, this error message appears:

<!-- -->

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

-   If the string contains more than 79 characters, this error message appears:

<!-- -->

    SN--005: Type is too long

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

A :STARTVALUE block is not required as a direct member of the :FONSTSTYLE block. If present, then there must be only one instance and it must preceed any :LINEPROC block or any :ENDVALUE block which is a direct member of the :FONTSTYLE block or this error message results:

    SN--083: Expecting :efontstyle tag

A :LINEPROC block is not required as a direct member of the :FONSTSTYLE block. More than one may be present. If present, they must all preceed any :ENDVALUE block which is a direct member of the :FONTSTYLE block (or the last :LINEPROC block must be the last block in the :FONTSTYLE block) or this error message results:

    SN--083: Expecting :efontstyle tag

An :ENDVALUE block is not required as a direct member of the :FONTSTYLE block. If present, then there must be only one instance and it must follow any :LINEPROC block or any :STARTVALUE block which is a direct member of the :FONTSTYLE block or this error message results:

    SN--083: Expecting :efontstyle tag

The gross structure of the :FONTSTYLE block can be described in this way:

-   The attribute **type** must be present and must be first.
-   None of the included blocks are required, separately or together. A :FONTSTYLE block can consist of the attribute **type** alone. The :STARTVALUE block, if present, must be directly after the attribute.
-   The :LINEPROC block(s), if present, must be after the :STARTVALUE block and before the :ENDVALUE block.
-   The :ENDVALUE block, if present, must be the last item in the :FONTSTYLE block.

The :LINEPROC block has its own internal structure, which will now be discussed.

The attribute **pass** is required.

The attribute **pass** is a natural number. It can be entered as a decimal integer or as a hexadecimal integer with prefix **$**.

The values of attribute **pass** are subject to these restrictions:

-   A negative value produces this error message:

<!-- -->

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

-   A value of "0" produces this error message:

<!-- -->

    SN--086: Invalid pass number

-   If the first :LINEPROC block has a value other than "1", then this error message results:

<!-- -->

    SN--086: Invalid pass number

-   If each subsequent :LINEPROC block does not have a value greater than the value of the previous :LINEPROC block plus one, then this error message results:

<!-- -->

    SN--086: Invalid pass number

-   A :LINEPROC block with a value equal to the value in a previous :LINEPROC block produces this error message:

<!-- -->

    SN--087: 2 lineproc blocks with identical pass numbers

It is not known what the upper limit is: short of creating $100 :LINEPROC blocks, there is no way to be certain if it can be larger, and the same applies to higher limits. However, large numbers of line passes are not very likely; and, indeed, the highest value of attribute **pass** observed in the existing source files is "3".

The :STARTVALUE block is not required. If present, then there must be only one instance and it must immediately follow the attribute **pass** or this error message results:

    SN--085: Expecting :elineproc tag

The :FIRSTWORD block is not required. If present, then there must be only one instance and it must follow the attribute **pass** and the :STARTVALUE block (if present) or this error message results:

    SN--085: Expecting :elineproc tag

The :STARTWORD block is not required. If present, then there must be only one instance and it must follow the attribute **pass**, the :STARTVALUE block (if present), and the :FIRSTWORD block (if present) or this error message results:

    SN--085: Expecting :elineproc tag

The :ENDWORD block is not required. If present, then there must be only one instance and it must either be the last included block or preceed the :ENDVALUE block (if present) or this error message results:

    SN--085: Expecting :elineproc tag

The :ENDVALUE block is not required. If present, then there must be only one instance and it must be the last included block or this error message results:

    SN--085: Expecting :elineproc tag

The :STARTVALUE and :ENDVALUE blocks are also used outside of the :LINEPROC block in the :FONTSTYLE block proper. The :FIRSTWORD, :STARTWORD and :ENDWORD blocks can only appear within a :LINEPROC block.

The structure of the :LINEPROC block can be described in this way:

-   The attribute **pass** must be present, must be first, and its value must start with "1" and increase by "1" in each succeeding :LINEPROC block.
-   None of the included blocks are required, separately or together. A :LINEPROC block can consist only of the attribute **pass**.
-   Those included blocks which are present must all follow the attribute **pass** and appear in this order: :STARTVALUE, :FIRSTWORD, :STARTWORD, :ENDWORD, :ENDVALUE.

These are notes made while examining the available examples; they are intended to provide an initial conceptual framwork for understanding the :FONTSTYLE block. Further testing will be needed before they can be used to document the :FONTSTYLE block.

It is helpful to keep in mind that the :DRIVER block describes the actions needed to be taken to produce a desired effect on an actual output device, such as a printer. Even the WHLPDRV.PCD file, which targets WHLPCVT.EXE as it's "device", or the PSDRV.PCD file, which targets PostScript files and so is actually a code generator for any number of printers and whose output can be converted Acrobat .PDF files and never encounter an actual printer, or the TERMDRV.PCD file, which targets the "terminal", that is, the computer's display as seen in a command session window, can be viewed in this way.

The term "pass" appears to be used here as applying to the number of times the same line will be printed out. That is, wgml is presumed to print each line once for each "pass", following the instructions in the various CodeBlocks. This usage is not the same as the number of passes through a document, or of the number of passes used in creating help files for OpenWatcom. For this reason, the phrases "document pass" and "line pass" will be used to distinguish between the passes through a document and the passes over the line being output.

The :STARTVALUE block may or may not have a corresponding :ENDVALUE block; this presumably depends on whether or not the :STARTVALUE block changes the device state such that an :ENDVALUE block is needed to reverse the change. Devices that implement, for example, "bold", by overprinting appear to have two :LINEPROC blocks (line pass 1 and line pass 2) with a :STARTVALUE block only which, presumably, prints out the current line, once for each line pass, and which requires no :ENDVALUE block because the device state is not changed.

A :FIRSTWORD block can also change the device state such that an :ENDVALUE block is needed to reverse the change: so an :ENDVALUE block can be used even when no :STARTVALUE block appears.

The :FIRSTWORD/:STARTWORD/:ENDWORD blocks appear to work in this manner:

-   The :FIRSTWORD block is usually found with the "uline" and "ulbold" styles, and so presumbly is used primarily to turn underlining on at the start of the text (as opposed to any preceding spaces). Spaces embedded in the text would be underlined. However, it also appears in a few cases before :STARTWORD, where it appears to be used to position the printhead and perhaps to issue a specific device command code.
-   The :STARTWORD/:ENDWORD blocks are invariably found with the "uscore" and "usbold" styles. Presumably, the result is that each word is underlined but the spaces between them are not.

It is possible for :FIRSTWORD to appear on line pass 1 and :STARTWORD/:ENDWORD to appear on line pass 2. In at least one instance, the line pass 2 action appears to be to actually print the underline characters under the word while the line pass 1 action appears to be to print the entire line out.

The binary file encoding is interesting. The FontstyleGroup struct is:

    FontstyleGroup {
        uint8_t             data_count;
        uint16_t            fontstyle_count;
        ShortFontstyleBlock first_fontstyle;
        FontstyleBlock      fontstyle[fontstyle_count-1];
    }

The field **data\_count** contains the number of bytes, following **data\_count**, up through and including the null byte terminating the field **first\_fontstyle.type**.

The field **fontstyle\_count** contains the number of :FONTSTYLE blocks encountered in the source file plus 1 if none of the blocks had the value PLAIN for the value of the attribute **type**. Thus, it will always have at least "1" as its value.

The field **first\_fontstyle** contains the first ShortFontstyleBlock instance. It will always be present.

The field **fontstyle** contains the FontstyleBlocks encoding the remaining :FONTSTYLE blocks. There may, of course, not be any.

The FontstyleBlock struct is:

    FontstyleBlock {
        uint8_t             data_count;
        ShortFontstyleBlock fontstyle;
    }

The field **data\_count** contains the number of bytes, following **data\_count**, up through and including the null byte terminating the field **fonststyle.type**.

The field **fontstyle** contains the ShortFontstyleBlock encoding whichever :FONTSTYLE block this FontstyleBlock instance encodes.

The ShortFontstyleBlock struct is:

    ShortFontstyleBlock {
        uint16_t        line_passes;
        uint16_t        unknown_count = { 0x0001 };
        uint8_t         nulls[2] = { 0x00, 0x00 };
        uint8_t         type[varies];
        FontstyleFuncs  fontstylefuncs;
    }

The field **line\_passes** contains the number of line passes (or the number of :LINEPROC blocks) in the encoded :FONTSTYLE block. Given the restrictions on line pass numbers noted above, this is also the largest value of attribute **pass** which will be encountered.

The field **unknown\_count** may or may not be a count; it always has the value shown.

The field **nulls** may or may not have some actual meaning, but is always composed of nulls.

The field **type** is a null-terminated string. For FontStyleBlocks.firstFontstyle, it's length, including the terminating null byte, will be FontstyleBlocks.data\_count - 8. For FontStyle.fontstyle, it's length, including the terminating null byte, will be FontStyle.data\_count - 6. An empty string will be parsed as a NULL pointer.

The field **fontstylefuncs** is a Variant B FunctionsBlock, for the details of which see [Variant B FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-B). Also see [Multiple Codeblocks](WGML-Device-Functions#Multiple-CodeBlocks) for the problem of a single "junk byte" between CodeBlocks and my current intentions for dealing with it.

The order in which :FONTSTYLE blocks and their contents are encoded can be summarized this way:

-   The :FONTSTYLE blocks are encoded in the reverse of their order in the source file.
-   The :FONTSTYLE-level :STARTVALUE and :ENDVALUE blocks (if present) are the first two CodeBlocks and the :STARTVALUE block's CodeBlock is always first: these blocks are never inverted.
-   Any :LINEPROC blocks present are then encoded in order by increasing value of the attribute **pass**.

Within the :LINEPROC block, the order of any blocks that are present requires some explanation:

-   Within a :LINEPROC block, :STARTVALUE/:ENDVALUE pairs are never inverted.
-   These pairs can be inverted in the binary file:

<!-- -->

    :STARTWORD/:ENDWORD
    :FIRSTWORD/:ENDVALUE
    :FIRSTWORD/:ENDWORD
    :STARTWORD/:ENDVALUE

-   For inversion to occur, the :LINEPROC must contain the %textpass() device function. Other device functions may be present in the same block as the %textpass() device function.

Since the device functions %ulineoff() and %ulineon() are not allowed in the same :LINEPROC as the device function %textpass(), it is possible that gendev is delaying the compilation of the other blocks when a %textpass() is found until it can be quite certain that no %ulineoff() or %ulineon() function is present, and then, in effect, popping the LIFO stack and compiling the other blocks in the inverted order. At any rate, if wgml4 turns out to need the blocks inverted, our gendev will be able to invert them.

There are three special situations:

-   The ShortFontstyleBlock for the value PLAIN of field **type**.
-   A :FONTSTYLE block containing only the attribute **type**.
-   A :LINEPROC block containing only the attribute **pass**.

These notes pertain to the value PLAIN:

-   There is always a block in the binary file with value "plain" for the field **type**.
-   If there is a :FONTSTYLE block in the source file with value PLAIN for it's attribute **type**, then the corresponding ShortFontstyleBlock instance is placed and constructed like any other.
-   If there is no :FONTSTYLE block in the source file with value PLAIN for it's attribute **type**, whether other :FONTSTYLE blocks exist or not, then the value of the field **first\_fontstyle.codeblocks.count** will be "0x0000".

For more details on how a :FONTSTYLE block consisting solely of the attribute **type** is encoded, see [this](WGML-Device-Functions#Empty-FunctionsBlocks) section.

The third case, a :LINEPROC block consisting solely of the attribute **pass**, produces this CodeBlock:

    08
    00 00 01 00
    00 00

As discussed in [CodeBlock Structure](WGML-Device-Functions#CodeBlock-Structure), the first byte is the designator for a CodeBlock encoding an :ENDVALUE block within a :LINEPROC block. The next line consists in two nulls and the line pass number. The last line is the **count** field, which is zero, and which is followed immediately by the next CodeBlock (if any: since the next CodeBlock will be the first for the next line pass, and there may or may not be a next line pass, there may or may not be a "next CodeBlock", in which case this will be the last CodeBlock in this FontstyleFuncs instance).

The :FONTSWITCH Block
---------------------

This appears to be exactly as described in [WGML 4 Reference](WGML-References#reference1):

    :FONTSWITCH
       type
       :startvalue.
          <device functions>
       :estartvalue.
       :endvalue.
          <device functions>
       :eendvalue.
    :eFONTSWITCH.

This block is not required.

If a :FONTSWITCH block is present, then the attribute **type** is required. Its value can be an empty string; if it is not, then it must have less than 80 characters, or this error message results:

    SN--005: Type is too long.

If either a :STARTVALUE block is not present, whether an :ENDVALUE block is present or not, or if both are present but the :ENDVALUE block is placed before the :STARTVALUE block, this error message results:

    SN--015: Expecting :startvalue tag

However, an :ENDVALUE block is not required.

If multiple :STARTVALUE blocks or :ENDVALUE blocks are present, this error message occurs, with a reference to the line containing the second :STARTVALUE or :ENDVALUE tag:

    SN--018: Expecting :efontswitch tag

(if both multiple :STARTVALUE blocks and multiple :ENDVALUE blocks are present, the error is associated with the second :STARTVALUE tag).

Thus, each :FONTSWITCH must contain first the attribute **type** and then the :STARTVALUE block. It may also contain an :ENDVALUE block.

The corresponding struct in the binary file is:

    FontswitchFuncs {
        uint16_t           count;
        FontswitchBlock    fontswitchblocks[count];
    }

This is a [Variant C FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-C).

The value of the field **count** will be the number of FontswitchBlocks in the FontswitchFuncs instance.

The field **fontswitchblocks** is an array containing one FontswitchBlock per :FONTSWITCH block in the source file.

The struct FontswitchBlock is:

    FontswitchBlock {
        uint8_t        type[up to 80];
        uint8_t        flags[21];
        uint16_t       count;
        CodeBlock      codeblock[count];
    };

The field **type** contains a null-terminated string containing the value of the attribute **type**. An empty string is parsed as a NULL pointer.

The field **flags** is discussed [here](#The-Device-Function-Flags).

Initial testing suggested that, if the value of the attribute **type** had 78 or 79 characters, then the field **type** would only have the first 78 characters and would have no terminating null. Both of these statements, however, turned out to be incorrect when testing was done using the %wgml\_header() function, which makes the first entry in the flags array become "0x01". No doubt I was mis-counting the flag bytes in the past and got confused.

The value of the field **count** is the number of CodeBlocks contained in this FontswitchBlock. There will be, at most, two of them: the first (or only) will always be from the required :STARTVALUE block and the second (if present) will be from the optional :ENDVALUE block.

If there are multiple :FONTSWITCH blocks, they will be placed in the binary file in the *reverse* order from the order in which they occur in the source file.

If no :FONTSWITCH block is present in the source file, then a FontswitchFuncs instance with field **count** equal to "0x0000" will be present.

The :HLINE Block
----------------

This appears to be exactly as described in [WGML 4 Reference](WGML-References#reference1):

    :HLINE
       thickness
       :value.
          <device functions>
       :evalue.
    :eHLINE.

This block is not required.

If the :HLINE block is present, then the attribute **thickness** is required.

If the :HLINE block is present, then the :VALUE block is required: if no :VALUE block is present, this error message results:

    SN--055: Expecting :value tag

However, only one :VALUE block is allowed: if more than one exists, this error message appears with the number of the line on which the second :VALUE tag is located:

    SN--072: Expecting :ehline tag

The corresponding struct in the binary file is:

    HlineBlock {
     FunctionsBlock functions;
     ThicknessBlock thickness;
    }

The field **functions** is a [Variant A FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-A).

If the :HLINE block is present in the source file then, since exactly one :VALUE block is required to be present inside it, there will be exactly one CodeBlock and field **functions.count** will have the value "0x0001".

The field **thickness** is a [ThicknessBlock](#The-ThicknessBlock).

If no :HLINE block is present in the source file then the field **functions.count** will be "0x0000" and there will be no [ThicknessBlock](#The-ThicknessBlock) at all -- the next P-buffer will follow immediately.

The :HTAB Block
---------------

This appears to be exactly as described in [WGML 4 Reference](WGML-References#reference1):

    :HTAB
       :value.
          <device functions>
       :evalue.
    :eHTAB.

This block is not required.

If the :HTAB block is present, then the :VALUE block within it is required: if no :VALUE block is present, this error message results:

    SN--055: Expecting :value tag

Only one :VALUE block is allowed: if more than one exists, this error message appears with the number of the line on which the second :VALUE tag is located:

    SN--013: Expecting :ehtab tag

When the :HTAB block is present in the source file, it is encoded as [Variant A FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-A).

When the :HTAB block is present in the source file, the field **count** of the FunctionsBlock will be "0x0001" because the :HTAB block will contain one and only one :VALUE block, producing exactly one CodeBlock.

If no :HTAB block is present in the source file, then the field **count** of the FunctionsBlock will be "0x0000".

The :INIT Block
---------------

The description in [WGML 4 Reference](WGML-References#reference1) appears to still be correct:

    :INIT
       place
       :value.
          <device functions>
       :evalue.
       :fontvalue.
          <device functions>
       :efontvalue.
    :eINIT.

The :INIT block is not required.

If an :INIT block is present, then the value of the attribute **place** is one of these character strings:

-   START
-   DOCUMENT

If an :INIT block is present, then the attribute **place** is required.

If an :INIT block is present, then at least one of the :VALUE or :FONTVALUE blocks must be present; if only the attribute **place** is present, this error meesage occurs:

    SN--055: Expecting :value tag

If an :INIT block is present, then any number of :VALUE and/or :FONTVALUE blocks may be present, in any order (so long as the attribute **place** preceeds all of them). Each such block will become a CodeBlock.

The corresponding struct in the binary file is:

    InitFuncs {
        uint16_t       count;
        InitBlock      initblock[count];
    }

This is a [Variant C FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-C).

If either an :INIT block with the value START for the attribute **place** or an :INIT block with the value DOCUMENT for the attribute **place** (but not both) is present in the source file then the field **count** will have the value "0x0001".

If both :INIT blocks are present in the source file then the field **count** will have the value "0x0002". Note that there can be, at most, two :INIT blocks, one for each value of the attribute **place**.

The structure InitBlock is:

    InitBlock {
        uint8_t        designator;
        uint16_t       count;
        CodeBlock      codeblock[count];
    };

The value of the field **designator** depends on the value of the attribute **place**: it is "0x01" for START and "0x02" for DOCUMENT.

The value of the field **count** is the number of CodeBlocks contained in this InitBlock. Since multiple :VALUE and :FONTVALUE blocks are allowed in an :INIT block, and since each :VALUE or :FONTVALUE block becomes a CodeBlock, this value is limited only by being a single byte. The CodeBlocks will appear in the order that the :VALUE and :FONTVALUE blocks appeared in the source file: when searching for :VALUE CodeBlocks, all must be examined because a :FONTVALUE CodeBlock can preceed or follow a :VALUE CodeBlock..

If there are two :INIT blocks, then in the binary file, the InitBlock encoding the :INIT block with the value START for the attribute **place** will always be found first, even if the :INIT block with the value DOCUMENT for the attribute **place** comes first in the source file.

If no :INIT block is present in the source file, then the field **count** of InitFuncs will have the value "0x0000".

The test device/driver revealed that each CodeBlock is executed in order, which, of course, reflects the order of the :VALUE and :FONTVALUE blocks in the :INIT block. It also showed that the CodeBlocks which result from :FONTVALUE blocks are invoked multiple times: once for each :DEFAULTFONT block and, if the :UNDERSCORE block is present and provides a font name instead of a font number once for the font it names. The net result: wgml needs the exact order preserved, and needs to know which CodeBlocks come from :VALUE blocks and which from :FONTVALUE blocks.

Examination of the available :INIT blocks shows these results:

-   Very few drivers use an :INIT block with the value DOCUMENT for the attribute **place**; those that do also have an :INIT block with the value START for the attribute **place**.
-   Very few :INIT blocks have a :FONTVALUE block; those that do also have a :VALUE block.
-   The :INIT block with the value START for the attribute **place** in PSDRV.PCD contains one :VALUE block followed by one :FONTVALUE block.
-   Two HP-related drivers contain :INIT blocks with multiple :VALUE and multiple :FONTVALUE blocks, so this can happen, but is rare.
-   Some :DRIVER blocks contain no :INIT blocks at all: it truly is optional.

The :NEWLINE Block
------------------

This appears to be exactly as described in [WGML 4 Reference](WGML-References#reference1):

    :NEWLINE
       advance
       :value.
          <device functions>
       :evalue.
    :eNEWLINE.

If no :ABSOLUTEADDRESS block exists in the source file, then a :NEWLINE block with the value of the attribute **advance** set to "1" must be present. This is the only change noted in the README file produceable from the [WGML 3.33 Update](WGML-References#reference2); this is a change from [WGML 4 Reference](WGML-References#reference1), which states that "\[a\] newline block with an advance value of one must be specified".

If a :NEWLINE block is present, then the attribute **advance** is required.

If a :NEWLINE block is present, then the value of the attribute **advance** is an unsigned integer: a negative number produces the error message

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

The upper limit depends on the version: for version 3.33 it is $CCCF and for version 4.1 the upper limit was not determined but values above $FFFF wrap.

If a :NEWLINE block is present, then the :VALUE block is required: if it is not present, the this error message appears:

    SN--055: Expecting :value tag

If more than one :VALUE block is present, the second triggers this error message:

    SN--011: Expecting :enewline tag

The corresponding struct in the binary file is:

    NewlineFuncs {
        uint16_t       count;
        NewlineBlock   newlineblocks[count];
    }

This is a [Variant C FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-C).

The value of the field **count** will be the number of elements in the field **newline** considered as an array.

The field **newlineblocks** is an array of NewlineBlock instances, each of which encodes one :NEWLINE block present in the source file.

The structure NewlineBlock is:

    NewlineBlock {
        uint16_t       advance;
        uint16_t       count;
        CodeBlock      codeblock[count];
    };

The value of the field **advance** is the value of the attribute **advance**. In version 3.33, $CCCF is the largest value accepted by gendev; in version 4.1, all values tried were accepted but the result (if larger than $FFFF) wrapped.

The value of the field **count** is the number of CodeBlocks contained in this InitBlock. Since a :VALUE block is required and only one :VALUE block is allowed, it will always be "0x01 0x00".

The field **codeblock** contains the CodeBlock.

The NewlineBlocks are ordered in the binary file by the value of the attribute (and so of the field) **advance**, not by their order in the source file. Intriguingly, :NEWLINE blocks with values of the attribute **advance** higher than "$7FFF" are placed before :NEWLINE blocks with values of the attribute **advance** below "$8000". The first bit, that is, the bit used in signed integers to indicate the sign, is set from "$8000" on up: gendev appears to be treating these values as negative numbers when it comes to ordering the NewlineBlocks. Whether wgml considers such values to be negative in any way may or may not be worth testing: realistically, a command to advance the paper by $8000 lines is not too likely to be used.

If no :NEWLINE block is present in the source file, then then the field **count** of the NewlineFuncs struct will have the value "0x0000".

The :NEWPAGE Block
------------------

This appears to be exactly as described in [WGML 4 Reference](WGML-References#reference1):

    :NEWPAGE
       :value.
          <device functions>
       :evalue.
    :eNEWPAGE.

This block is required, as is the :VALUE block within it: if no :VALUE block is present, this error message results:

    SN--055: Expecting :value tag

However, only one :VALUE block is allowed: if more than one exists, this error message appears with the number of the line on which the second :VALUE tag is located:

    SN--012: Expecting :enewpage tag

The :NEWPAGE block is encoded by a [Variant A FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-A).

The field **count** of the FunctionsBlock will be "0x0001" because the :NEWPAGE block will contain one and only one :VALUE block, producing exactly one CodeBlock.

The :PAGEADDRESS Block
----------------------

This appears to be exactly as described in the[WGML 4 Reference](WGML-References#reference1):

    :PAGEADDRESS
       x_positive
       y_positive
    :ePAGEADDRESS.

The :PAGEADDRESS block is not required.

If the :PAGEADDRESS block is present, then both attributes are required. They can each take one of two character string values:

-   YES
-   NO

If any other value is given this error message results:

    AT--003: Invalid attribute value

The corresponding struct in the binary file is:

    PageaddressBlock {
       uint8_t x_positive;
       uint8_t y_positive;
       uint8_t null = { 0x00 };
    }

The value YES is encoded as "0x01". The value NO is encoded as "0x00". If no :PAGEADDRESS block is present, both values are "0x01"; they are always present.

The field **null** is included for tidyness and because it has no other apparent function.

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

The ThicknessBlock
------------------

The ThicknessBlock is used to encode the attribute **thickness** found in these sub-blocks of the :DRIVER block:

-   The :DBOX block.
-   The :HLINE block.
-   The :VLINE block.

The ThicknessBlock structure varies with the file version.

For gendev 3.33 it is:

    ThicknessBlock {
     uint8_t        count = { 0x02 };
     uint16_t       thickness;
    }

For gendev 4.1 it is:

    ThicknessBlock {
     uint8_t        count = { 0x04 };
     uint32_t       thickness;
    }

The field **count** contains the number of bytes used to encode the attribute **thickness**.

The field **thickness** is a two- or four-byte unsigned integer containing the value of the attribute **thickness**.

The :VLINE Block
----------------

This appears to be exactly as described in [WGML 4 Reference](WGML-References#reference1):

    :VLINE
       thickness
       :value.
          <device functions>
       :evalue.
    :eVLINE.

This block is not required.

If the :VLINE block is present, then the attribute **thickness** is required.

If the :VLINE block is present, then the :VALUE block within it is required: if no :VALUE block is present, this error message results:

    SN--055: Expecting :value tag

Only one :VALUE block is allowed: if more than one exists, this error message appears with the number of the line on which the second :VALUE tag is located:

    SN--073: Expecting :evline tag

The corresponding struct in the binary file is:

    VlineBlock {
     FunctionsBlock functions;
     ThicknessBlock thickness
    }

The field **functions** is a [Variant A FunctionsBlock](WGML-Device-Functions#FunctionsBlock-Variant-A).

If the :VLINE block is present in the source file then, since exactly one :VALUE block is required to be present inside it, there will be exactly one CodeBlock and field **functions.count** will have the value "0x0001".

The field **thickness** is a [ThicknessBlock](#The-ThicknessBlock).

If no :VLINE block is present in the source file then the field **functions.count** will be "0x0000" and there will be no [ThicknessBlock](#The-ThicknessBlock) at all -- the next P-buffer will follow immediately.
