Skip to content

WGML Driver File Blocks

Jiri Malak edited this page Feb 20, 2021 · 5 revisions
Table of Contents

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.

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 "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 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:

: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.

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.

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 at all -- all that will be left are the final nulls.

The Device Function Flags

The :FONTSTYLE and :FONTSWITCH 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 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 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.

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 there are two error messages (SN-084 and SN-088) referencing :FONTSTYLE. In the READ ME file produceable from the WGML 3.33 Update 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 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. Also see 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 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, 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:

: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.

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.

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:

: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.

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.

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

The :HTAB Block

This appears to be exactly as described in WGML 4 Reference:

: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.

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

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:

: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; this is a change from WGML 4 Reference, 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.

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:

: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.

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 theWGML 4 Reference:

: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 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:

: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.

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.

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

Clone this wiki locally