Skip to content

WGML Device File Blocks

Jiří Malák edited this page Feb 19, 2021 · 7 revisions
Table of Contents

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.

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

The :BOX Block

The :BOX block was changed from that shown in WGML 4 Reference by the README file produceable from the WGML 3.33 Update. 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 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 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 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: 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 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 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 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 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 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 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.

The :OUTTRANS Block

This block is described in 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 or in the README file produceable from the WGML 3.33 Update. 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 discusses this block in a larger context.

The :PAGESTART Block

The description of the :PAGESTART block given in WGML 4 Reference 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 discusses this block in a larger context.

The :PAUSE Block

The description of the :PAUSE block given in WGML 4 Reference 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.

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.

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 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 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, 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 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 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 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.
Clone this wiki locally