GML Tag Notes

From Open Watcom

Jump to: navigation, search

Contents

Introduction

This page is intended to accumulate notes on how wgml 4.0 uses the various tags. The information presented here should be used to update the WGML Reference so that it actually describes wgml 4.0.

Since I have been working with those tags used with the device library, the entries will include and may well be dominated by those tags. It might be wondered how the information here differs from that presented in discussing the device library.

The pages which deal with the device library are concerned primarily with where the tags appear in the source file and how they are encoded in the binary file. This page is intended to discuss how those tags (or, more correctly, the blocks defined by these tags) are used by wgml 4.0.

:FONTPAUSE

The WGML Reference states in section 15.10.3.3 FONTPAUSE Attribute:

The fontpause attribute specifies a character value which is the 
font pausing method to be used when switching into the font.

and in section 15.10.5 FONTPAUSE Block:

In some cases, the font switch may require physical intervention 
at the output device by the operator. Examples of such an
intervention would be changing a print wheel or color ribbon. 

This section uses terminology discussed here to describe the various blocks.

With my test device and test driver files I used ten test font files. For each of these fonts, a separate :FONTPAUSE was defined. Since the fonts were numbered from "01" to "10", the :FONTPAUSE blocks were named (that is, had for their value of attribute type) "pause01" through "pause10". These fonts were used in specific contexts:

  • "01" through "06" were used with :DEFAULTFONT blocks 0 through 5 (and so paired with font styles "plain", "bold", "uline", "uscore", "ulbold", and "usbold" respectively).
  • "07" and "08" were used with the :BOX and :UNDERSCORE blocks, respectively.
  • "09" and "10" were reserved for used with the command-line FONT option.

Each :FONTPAUSE block was configured to identify itself when interpreted by wgml 4.0. The "pause02" block was also used to contain the function sequences being tested; a "FONT" line in default.opt, was used to vary the font used with the :DEFAULTFONT 0 (and so interpreted first) between font "01" and font "02", which aided in testing.

The results reported here can be expanded to show which :FONTPAUSE corresponded to which intance:

The output for the two situations with minimal :FONTPAUSE blocks was:

instance "pause01" is first   "pause02" is first
   1     pause01              pause02  
   2     pause04              pause04
   3     pause08              pause08
   4     pause04              pause04
   5     pause08              pause08
   6     pause04              pause04
   7     pause01              pause02
   8     pause02              pause02
   9     pause01              pause02
  10     pause02              pause02
  11     pause01              pause02

The variation between "pause04" and "pause08" is the result of using the corresponding :DEVICEFONTs for the :FONTSTYLE with the value "uscore" for its attribute type ("pause04") and for the value of attribute font in the :UNDERSCORE block ("pause08").

As discussed here, the only change occurs when both fonts (those using "pause01" and "pause02" in the first column and those using "pause02" in the second column) use the style "plain": the last two "pause02" lines disappear, a result of the fact that font style "plain" only requires one pass while font style "bold" requires two. This, of course, means that when a :FONTPAUSE is interpreted depends not only on the :DEVICEFONT it is associated with and the font switching process but also on the font style it is associated with in the :DEFAULTFONT block, making the description quoted above not quite complete. Of course, the font style does this by requiring multiple passes, which in turn require additional font switches, so the description is correct as far as it goes.

The discussion here also notes that a :FONTPAUSE will be interpreted, in some instances, even when the :FONTSWITCH blocks are not. One of those situations, as might be expected, is that the fonts being switched are the same font. The problem is that they can be associated with different font styles.

If the example given above of manually changing the ribbon, so that, for example, :FONTSTYLE "bold" prints text in red while :FONTSTYLE "plain" does not, then associating the same :FONTPAUSE with both :FONTSTYLE instances is going to cause problems: the operator will not be able to tell whether to change the ribbon or not.

The only tool available to distinguish between the two :FONTSTYLE instances is the device function %font_number(). Unfortunately, the command line option FONT can remap both the font and the font style assigned to a given :DEFAULTFONT and so to a particular %font_number(). What is really needed is a %font_style() function, but none exists.

The net effect is that, if a :FONTPAUSE is needed, it may be a very bad idea to use the corresponding font (that is, :DEVICEFONT, which maps the font name to the font pause) with more than one :FONTSTLYE or more than one :DEFAULTFONT (which maps the :DEVICEFONT to a :FONTSTYLE), depending on just what the :FONTPAUSE is intended to accomplish.

Implementation Notes

The :FONTPAUSE block occupies a very odd position: there is no need to implement it at all, since it is not used in any :DEVICE block known to me; and yet it is so useful in analysing the use of the :FONTSWITCH and :FONTSTYLE blocks that, inevitably, it's implementation in wgml 4.0 is also made quite clear:

The :FONTPAUSE block is interpreted whenever a font switch is 
called for. When the font switch occurs, then the :FONTPAUSE 
is interpreted after the :ENDVALUE block of the font being switched
from (if any) and before the :STARTVALUE block of the font being
switched to; even if the font switch does not actually occur, the
:FONTPAUSE block is still interpreted. 

The situations in which a font switch does not actually occur when called for are discussed here.

:FONTSTYLE

This block is not documented in the WGML Reference. As a result, a detailed examination of how it and each of its sub-blocks is used is unavoidable. This may take some time to assemble and organize properly.

The :STARTVALUE Block

This section discusses the :FONTSTYLE block :STARTVALUE block. The :LINEPROC block also has a :STARTVALUE block; it is discussed in its own section.

There is reason to believe that the :FONTSTYLE block :STARTVALUE and :ENDVALUE blocks are not intended to be used as an ON/OFF pair: when an extremely simple test file, one containing nothing but text organized into paragraphs with the :P. tag (that is, no header, no title, no TOC, no index, no footers, no markup), was processed and examined, the :FONTSTYLE block :ENDVALUE block never appeared. The :FONTSTYLE block :STARTVALUE block, on the other hand, appeared at the start of each text line.

The :FONTSTYLE block :STARTVALUE block is always followed immediately by the :LINEPROC block :STARTVALUE block. The :LINEPROC block :STARTVALUE block is usually preceeded immediately by the :FONTSTYLE block :STARTVALUE block; the exceptions are discussed here.

The :FONTSTYLE block :STARTVALUE block appears in these contexts:

  • As part of the action of device function %enterfont().
  • As part of the normal font switch sequence (but not of the alternate font switch, used with device functions %ulineon()/%ulineoff()).
  • As part of the first pass font style application sequence, when a font switch is not required.
  • As part of the subsequent pass font style application sequence, when a font switch is not required.
  • As part of the alternate font style application sequence, when a font switch is not required.

The :ENDVALUE Block

This section discusses the :FONTSTYLE block :ENDVALUE block. The :LINEPROC block also has an :ENDVALUE block in the :LINEPROC block; it is discussed in its own section.

The :ENDVALUE block occurs in these contexts:

It does not appear in this context:

  • The current font style is the last (or only) font style used in the TextLine.

It is, of course, this fact that prevents the :FONTSTYLE block :STARTVALUE and :ENDVALUE blocks from being used as an ON/OFF switch.

The context in which it is interpreted differs in the two cases listed above:

  • During a font switch, the :ENDVALUE block of the font style associated with the font being switched from is interpreted in the context of the font being switched to, with which it may or may not be associated (nothing prevents two :DEFAULTFONT blocks from associating the same font style with two different fonts).
  • During a subsequent pass, the :ENDVALUE block is interpreted outside of a font switch, and then it is interpreted in the context of the font it is associated with.

This suggests that the :ENDVALUE block should not depend on any of the device functions which return values associated with the current font.

Usage Notes

It is reasonably clear from the two prior sections that the :FONTSTYLE block STARTVALUE and :ENDVALUE blocks are not, in fact, used by wgml 4.0 as an ON/OFF switch.

On the other hand, the :DRIVER block in HELPDRV.PCD in the Open Watcom repository does this in font style "bold":

  • the :STARTVALUE block emits "0x1b" followed by "b", and
  • the :ENDVALUE block emits "0x1b" followed by "p"

which certainly looks like an ON/OFF switch switching the style to "bold" and back to "plain".

This can only work if the targeted device does not require that the :FONTSTYLE block STARTVALUE and :ENDVALUE blocks be used as an ON/OFF switch to function properly. Possible examples of how a device might do this are:

  • the device resets itself to its default state at the end of each line; or
  • the device has no memory: it can process these codes repeatedly and the effect is exactly the same as if it processed them once.

The :LINEPROC Block

These blocks define exactly what actions the device is to take to implement the font style. Each :LINEPROC block defines the actions to take on one specified pass of the print head over the paper (or equivalent action for devices that don't have print heads or use paper).

No :LINEPROC Present

The :LINEPROC block is entirely optional; if none is present, then wgml 4.0 behaves exactly as if this :LINEPROC block was present:

:LINEPROC
   pass = 1
   :STARTVALUE
       %textpass()
   :eSTARTVALUE
:eLINEPROC

Empty :LINEPROC Instances

At the very end of this section, it is noted that a :LINEPROC of this form:

:LINEPROC
   pass = 1
:eLINEPROC

is accepted and compiled by gendev 4.1 as if it contained an :ENDVALUE block with no device functions present.

When a font style using such a :LINEPROC block is used by wgml 4.0, however, the result is this message:

Abnormal program termination: Memory protection fault

regardless of which pass it is assigned to.

Examination of the output file shows that wgml 4.0 does not produce this error until it reaches the pass affected while printing out the text to which the font style is being applied.

Sub-block Usage

Since each :LINEPROC block must contain at least one sub-block, and since, as discussed here, each sub-block must contain at least one device function, the discussion now turns to the various sub-blocks, starting with an overview.

The :LINEPROC block contains five sub-blocks. Examination of the test documents show that, when a TextChars instance is being processed, they generally appear in these positions:

  • The :STARTVALUE block and :FIRSTWORD block appear either before the first TextChars instance of the line or before the first TextChars instance with a new value for field font_number is processed. If the :FIRSTWORD block is not defined, then the :STARTWORD block appears in its place. These blocks appear before the :STARTWORD block as such.
  • The :STARTWORD block appears before each TextChars instance which does not follow a font switch, even if this results in it appearing twice in a row because the :FIRSTWORD block is not defined.
  • The :ENDWORD block appears after each TextChars instance.
  • The :ENDVALUE block appears after the last TextChars instance (and after the :ENDWORD block).

To be specific, blocks which appear before the TextChars instance appear before the spaces (or :HTAB block or :ABSOLUTEADDRESS block) used to position the print head at the point where the first non-space character is to appear, unless, of course, device function %dotab() is involved.

From this, it appears that three ON/OFF switches exist:

  • The first pairs :STARTVALUE with :ENDVALUE, and applies to each set of consecutive TextChars instances with the same value for field font_number.
  • The second pairs :FIRSTWORD with :ENDVALUE, and applies to each set of consecutive TextChars instances with the same value for field font_number.
  • The third pairs :STARTWORD with :ENDWORD, and applies to most TextChars instances (those whose associated font style defines a :FIRSTWORD block and which follow a font switch are the exception).

The above reflects two observed rules:

  1. If the :FIRSTWORD block is not defined, then the :STARTWORD block appears in every context where the :FIRSTWORD block appears when it is defined, without known exception.
  2. When a font switch occurs, there is no :STARTWORD block (if a :FIRSTWORD block exists) or no second :STARTWORD block (if no :FIRSTWORD block exists).

It does not matter if the :FIRSTWORD block consists entirely of "%image('')", which produces no output or side effects of any kind; the only requirement is that it be defined.

The only exception to the second rule involves the drawing of the top line using :BOX block characters with tag :FIG and the Index (that is, in these cases no font switch occurred, and in no case did the second :STARTWORD block appear in drawing such lines). This probably means that the :STARTWORD block, as such, is not used when drawing horizontal or vertical lines using the characters defined in the :BOX block.

The :FIRSTWORD block and :ENDVALUE block are regularly used to implement underlining, that is, where every character in the affected phrase (but not any preceding whitespace) is underlined, including internal spaces.

The :STARTWORD block and :ENDWORD block are regularly used to implement underscoring, that is, where every non-space character in the affected phrase is underlined, but whitespace is not.

Considering the above information, these suggestions might be made:

  • When a :FIRSTWORD block is called for, if no such block is defined, then a :STARTWORD block is used instead. This suggests that :LINEPROC blocks which actually implement underscoring should not define a :FIRSTWORD block.
  • If a :FIRSTWORD block is defined, then, in some cases, no :STARTWORD block will appear. This suggests that :LINEPROC blocks which actually implement underlining should not define a :STARTWORD block.
  • If no :FIRSTWORD block is defined, then, in some cases, the :STARTWORD block will be interpreted twice in succession. This suggests that the :STARTWORD block, if defined, should be defined in such a way that it can be interpreted twice in succession without causing problems for the device.

The :STARTVALUE Block

As shown here, this block is the only place where device function %textpass() may be used; as noted here, whether or not that function is present determines whether or not the output text actually appears in the output file.

The :LINEPROC block :STARTVALUE block is usually preceded immediately by a :FONTSTYLE block :STARTVALUE block; known exceptions are:

  • In some cases, as part of the preparation for the first text line, as discussed here.
  • In some cases, as part of drawing a box using the characters in the :BOX block when processing tag .FIG, as discussed here.

The :LINEPROC block :STARTVALUE block is always followed immediately by the :LINEPROC block :FIRSTWORD block. Furthermore, the :LINEPROC block :FIRSTWORD block only appears when immediately preceded by the :LINEPROC block :STARTVALUE block.

Device function %ulineon() can also be placed in this block. The effect, as shown by the tests done so far, is indistinguishable from placing device function %ulineon() in the :FIRSTWORD block instead.

Unlike the :FIRSTWORD block, a :FONTSTYLE block which differs from the overprint "uscore" :FONTSTYLE block discussed below only in that the pass 2 :LINEPROC block has a :STARTVALUE block works normally, i.e., the first word is underscored.

This block is interpreted at the start of each TextChars instance which has a value for the field font_number which is different than the value in the prior TextChars instance. However, there is at least one context in which it is intepreted at the start of each TextChars instance, as discussed at the end of this section; although the appearance of the :STARTVALUE block is not mentioned, it does in fact appear each time just as the :ENDVALUE block does. A closer examination of this issue will eventually be done.

The :FIRSTWORD Block

The :LINEPROC block :FIRSTWORD block only appears when immediately preceded by the :LINEPROC block :STARTVALUE block. Furthermore, the :LINEPROC block :STARTVALUE block is always followed immediately by the :LINEPROC block :FIRSTWORD block.

As shown here, this block can contain device function %ulineon(); indeed, the overprint :FONTSTYLE "uline" discussed below does exactly that.

However, device function %ulineon() can also be placed in the :STARTVALUE block. The effect, as shown by the tests done so far, is indistinguishable from placing device function %ulineon() in the :FIRSTWORD block.

A :FONTSTYLE block which differs from the overprint "uscore" :FONTSTYLE block discussed below only in that the pass 2 :LINEPROC block has a :FIRSTWORD block results in the first word not being underscored. As noted at the end of the section on sub-block usage, it it generally best to implement only one of the :FIRSTWORD and :STARTWORD blocks.

This block can is also allowed to contain device function %ulineoff(). Since device function %ulineoff() must be preceded by device function %ulineon() in the same :LINEPROC block, the :STARTVALUE block must contain %ulineon() or gendev 4.0 will not process the source file.

When a :FONTSTYLE block with a pass 2 :LINEPROC block with a :STARTVALUE block containing device function %ulineon() and a :FIRSTWORD block containing device function %ulineoff() is tested, then the result is:

  • If the %ulineon() function is preceded by %dotab(), then the initial horizontal positioning (left margin) is output. Nothing else appears, although various :LINEPROC block sub-blocks are interepreted.
  • If the %ulineon() function is not preceded by %dotab(), then nothing whatsoever appears on the second pass, although various :LINEPROC block sub-blocks are interpreted (that is, a second pass does occur).

This block is interpreted at the start of each TextChars instance which has a different value for field font_number than the previous TextChars instance had. However, there is at least one context in which it is intepreted at the start of each TextChars instance, as discussed here. A closer examination of this issue will eventually be done.

The :STARTWORD Block

As shown here, this block can contain device function %ulineon(); indeed, the overprint :FONTSTYLE "uscore" discussed below does exactly that. And, if by "uscore" is meant a font style which underscores words but not spaces, then the :STARTWORD block is where device function %ulineon() needs to be.

This block is also able to contain device function %ulineoff(). Three cases exist, and the results are recorded here.

When a :FONTSTYLE block with a pass 2 :LINEPROC block with a :STARTVALUE block containing device function %ulineon() and a :STARTWORD block containing device function %ulineoff() is tested, and no :FIRSTWORD block is present, then the result is:

  • If the %ulineon() function is preceded by %dotab(), then the initial horizontal positioning (left margin) is output. Nothing else appears, although various :LINEPROC block sub-blocks are interepreted.
  • If the %ulineon() function is not preceded by %dotab(), then nothing whatsoever appears on the second pass, although various :LINEPROC block sub-blocks are interepreted (that is, a second pass does occur).

When a :FONTSTYLE block with a pass 2 :LINEPROC block with a :STARTVALUE block containing device function %ulineon() and a :STARTWORD block containing device function %ulineoff() is tested, and a :FIRSTWORD block is present, then the result is:

  • If the %ulineon() function is preceded by %dotab(), then the first word (only) is underscored.
  • If the %ulineon() function is not preceded by %dotab(), then the initial horizontal positioning (left margin) and the first word (only) are underscored.

These results also occur when the %ulineon() (with or without preceding %dotab()) is in the :FIRSTWORD block rather than the :STARTVALUE block.

This block is interpreted at the start of each TextChars instance, except as documented here.

The :ENDWORD Block

As shown here, this block can contain device function %ulineoff(). Indeed, the overprint "uscore" discussed below requires this block to contain device function %ulineoff() in order to work properly.

This block is interpreted at the end of each TextChars instance, that is, after the text has been output. When used with %ulineoff(), the observed behavior is much less clear, although the effect (stopping the output of underscore characters with the last character output previously) is quite clear. Additional research will need to be done.

The :ENDVALUE Block

As shown here, this block can contain device function %ulineoff(). Indeed, the overprint "uline" discussed below requires this block to contain device function %ulineoff() in order to work properly.

This block is interpreted in these contexts:

  1. As part of establishing the left margin before text output begins.
  2. As part of processing the first text line, but only when the indent is established before text output begins.
  3. As part of the sequence for processing text lines.
  4. Presumably as part of the sequence(s) for boxing, although this needs more work.
  5. As part of the "new font TextChars instance" sequence used in the first pass sequence.
  6. As part of the "new font TextChars instance" sequence used in the subsequent pass sequence as discussedhere.
  7. As part of the sequence used with device function %ulineon() and %ulineoff(), as discussedhere.
  8. At the end of the last text line. The value of %font_number(), %x_address() and %y_address() are the same as the preceding block. This is followed by the :FINISH block.

Implementing Font Styles

The implementation of a particular font style depends on the characteristics of the device.

Some devices define separate fonts for each style, which are then paired in the :DEFAULTFONT instances with font style "plain". Of course, this can lead to a very large number of :FONT blocks. The PS :DEVICE block does this for the "times" font.

Some devices perform some actions themselves. Thus, the WHELP :DEVICE block pairs the same :DEVICEFONT block with various :FONTSTYLE blocks -- and then implements those styles with a single :LINEPROC which uses the :STARTVALUE block and :ENDVALUE block as an ON/OFF switch to cause (presumably) the program WHLPCVT to implement the desired style.

Device PSDRV also provides definitions of the usual font styles which vary between having one :LINEPROC and using the :FIRSTWORD block and :ENDVALUE block for underlining and the :STARTWORD block and :ENDWORD block for underscoring, but in both cases emitting PostScript commands rather than using device functions %ulineon() and %ulineoff(). On the other hand, for font styles involving "bold", the two-pass approach discussed below is used.

It is clearly not possible to discuss all possible implementations of any particular style. The following sections will focus on implementations of font styles which rely entirely on the device functions and the behavior of wgml 4.0. For one thing, these are the definitions which are referred to by the page on sequencing, particularly (but not necessarily exclusively) the section on applying font styles.

A Font Style That Prints Nothing Out

This may seem like an odd choice, since no examples exist and it would seem to have no value beyond testing, but it does represent a minimal case.

This font style:

:FONTSTYLE
   type='redact'
   :LINEPROC
      pass=1
      :STARTVALUE
         %image('')
      :eSTARTVALUE
   :eLINEPROC
:eFONTSTYLE

is accepted by both gendev 4.1 and wgml 4.0, and, since the argument to device function %image() is an empty string, produces precisely nothing when applied.

As to utility, in theory, this could be used whenever it is necessary to maintain two versions of a document: one with all information included for internal use, and one with certain information redacted for external use. If the external version uses the above :FONTSTYLE for font style "redact", then blank places will occur where the material to be removed would otherwise have been. If the internal version uses a different version of :FONTSTYLE "redact", one which does an explicit or implicit %textpass(), then the internal version will show all the information. In practise, this would require a fair amount of thought and planning; however, text that is never printed is more secure than text which is printed and then blacked out.

Overprint "bold"

This :LINEPROC prints the same text twice, starting at the same position each time:

:FONTSTYLE
   type=bold
   :LINEPROC
      pass=1
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
   :LINEPROC
      pass=2
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
:eFONTSTYLE

The version used in testing had additional %image() statements to help in detecting the sequence of events.

Overprint "uline"

This :LINEPROC prints the text line once, and then prints underscore characters, starting at the same position each time:

:FONTSTYLE
   type=uline
   :LINEPROC
      pass=1 
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
   :LINEPROC
      pass=2
      :FIRSTWORD
         %dotab()
         %ulineon()
      :eFIRSTWORD
      :ENDVALUE
         %dotab()
         %ulineoff()
      :eENDVALUE
   :eLINEPROC
:eFONTSTYLE

Preliminary testing showed that this does, indeed, place the underscore character under every character included in the set of contiguous TextChars instances using this font style, including spaces between TextChars instances and any final TextChars instances which have no text but only generate spaces. Each TextChars instance is underlined separately. The initial horizontal positioning (left margin plus indentation), however, was not underlined.

Overprint "uscore"

This :LINEPROC prints the text line once, and then prints underscore characters under each word, starting at the same position each time:

:FONTSTYLE
   type=uscore
   :LINEPROC
      pass=1 
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
   :LINEPROC
      pass=2
      :STARTWORD
         %dotab()
         %ulineon()
      :eSTARTWORD
      :ENDWORD
         %dotab()
         %ulineoff()
      :eENDWORD
   :eLINEPROC
:eFONTSTYLE

Preliminary testing showed that this does, indeed, place the underscore character under each TextChars intance's text. For each TextChars instance, the horizontal positioning is done (using spaces only, never :HTAB, apparently) and then enough underscore characters are emitted to place one under each non-blank character in the TextChars instance's text.

Overprint "ulbold"

This :LINEPROC prints the text line once, and then prints underscore characters, and then prints the text line again, starting at the same position each time:

:FONTSTYLE
   type=ulbold
   :LINEPROC
      pass=1 
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
   :LINEPROC
      pass=2
      :FIRSTWORD
         %dotab()
         %ulineon()
      :eFIRSTWORD
      :ENDVALUE
         %dotab()
         %ulineoff()
      :eENDVALUE
   :eLINEPROC
   :LINEPROC
      pass=3
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
:eFONTSTYLE

At least, that is what should do. Testing proceeds.

In some cases, the "bold" part is done by issuing control codes to the device while the underlining is done as shown in pass 2 above.

Overprint "usbold"

This :LINEPROC prints the text line once, and then prints underscore characters under each word, and then prints the text line again, starting at the same position each time:

:FONTSTYLE
   type=usbold
   :LINEPROC
      pass=1 
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
   :LINEPROC
      pass=2
      :STARTWORD
         %dotab()
         %ulineon()
      :eSTARTWORD
      :ENDWORD
         %dotab()
         %ulineoff()
      :eENDWORD
   :eLINEPROC
   :LINEPROC
      pass=3
      :STARTVALUE
         %textpass()
      :eSTARTVALUE
   :eLINEPROC
:eFONTSTYLE

At least, that is what should do. Testing proceeds.

In some cases, the "bold" part is done by issuing control codes to the device while the underscoring is done as shown in pass 2 above.

Personal tools