Using Printer Drivers in Advanced Revelation 2.1

Published ByDateVersionKnowledge LevelKeywords
Revelation Technologies18 DEC 19912.1XEXPERTPRINT, DRIVERS, POSTSCRIPT

Advanced Revelation 2.1 introduces printer drivers into the product. This Technical Bulletin gives you a technical overview of how the printer drivers are implemented and provides documentation on system subroutines you may find useful.

Virtually all printers offer a variety of print styles and formats. For example, most offer both a "normal" and a "bold" weight, and many offer different styles such as italic or double-width. Many printers also offer a variety of fonts, whether in the form of "draft" and "near-letter quality" (for dot matrix printers) or recognized typefaces such as "serif" (often a form of Roman) and "sans serif" (popularly Helvetica or Swiss).

In almost all printers, you can control how and when a printer uses these different styles and typefaces by issuing "escape sequences" to the printer. Escape sequences for printers work much the same as they do for controlling screen attributes (see Technical Bulletin #4) certain sequences of characters (often preceded by an "escape" (ASCII character 27), hence the name) are interpreted by the printer not as text to be printed, but as commands. As a simple example, in the escape-sequence "language" understood by many Hewlett-Packard printers, the command to turn on bold printing is:

PRINT CHAR(27):"(s3B"

To send an escape sequence to your printer, you simply print it as you would any other string of characters. When the printer receives these characters, it recognizes the command and reacts accordingly.

Printer Drivers in Advanced Revelation Advanced Revelation Version 2.1 lets you create tables of these escape sequences and then use them automatically in your reporting. You can take advantage of these printer drivers in three ways:

  1. Establishing a default printer; in this case, all output to the printer will conform to the "normal" attributes of that printer.
  2. Specifying character formatting flags in Merge reports.
  3. Printing printer codes from within an R/BASIC program.

This technical bulletin concentrates on the last option, because that method provides the developer with the most control over printed output.

There are two issues in controlling your printer using escape sequences. The first is simply knowing what commands your printer understands and generating the appropriate escape sequences. For example, while you may understand that your printer can print in boldface, you will need to identify (and keep handy) the escape sequence required to turn boldface on and back off again when you want to resume normal printing.

The other issue is that of making your printing generic, that is, applicable to more than one printer. You may have multiple printers, or you may be creating an application to run in environments where the users can choose their own printers. In both cases, you need to be able to switch easily from printer to printer, preferably without having to recode, or even recompile, your programs.

Advanced Revelation's printer drivers keep you from having to worry about what kind of printer is being used. Rather than hard-coding printer control characters into your program you use the @ function in R/BASIC:

PRINT @(BOLDON$)

When the program is executed, the system automatically identifies ans sends the escape sequence required by the current printer. Your programs neither need to include the escape sequence that turns bold on, nor need to know which printer is active.

There are two parts to getting the proper output on paper. The first is the @ function. The second is the printer table.

The @ Function and Generic

Escape Codes The @ function is used to control special output characters. When you pass a negative number to the function, the system generates a so-called "generic escape code" (GEC). The GEC takes the form:

[Esc]Gxx

where [Esc] is a CHAR(27), G is the literal "G" and xx is a two byte code. For example, the function @(-50) produces the GEC:

[Esc]G2:CHAR(1)

This GEC is not specific to any one printer; it is, as implied by its name, a generic code. There is one GEC (and by implication, a different negative value) for each of the printer controls that Advanced Revelation understands (e.g. "start bold printing", "end bold printing", etc.). For example:

ValueCodeMeaning
-50[Esc]G2:CHAR(1)start bold
-51[Esc]G":CHAR(1)stop bold
-52[Esc]G2:CHAR(2)start italics
-53[Esc]G":CHAR(2)stop italics (etc.)

To make it easier to use the @ function, an insert record is provided in the INCLUDE file. PRINT_CONSTANTS maintains equated values for each of the negative values, so, for example, you don't have to remember that -50 is the code to turn on bold.

PRINT

If a printer driver is active, the R/BASIC command PRINT monitors the data being printed for the first two GEC characters ([Esc]+G). When these characters are encountered:

  • They are removed from the output stream, as are the next two characters.
  • The two characters following the [Esc-G] are used to look up the appropriate printer control information in a table maintained in memory.
  • The control information is then sent to the output device in place of the [Esc-G] sequence. In other words, the PRINT command swaps the GEC for the corresponding escape sequence for the current printer. Note that this substitution is done at the moment the data is being printed.

For example,if your printer driver defines [Esc](s0B (a Hewlett Packard code) as the sequence to turn bold on, the following steps are taken.

First, you write your program:

  $INSERT INCLUDE, PRINT_CONSTANTS
  PRINT @(BOLDON$): "BOLD TEXT"

When the program is executed, the @ function, generates an escape sequence based on the value of BOLDON$, -50:

[Esc]G2:CHAR(1)

Then when the PRINT statement sees this [Esc]Gxx string it substitutes:

[Esc](s0B

which is what a Hewlett Packard printer needs to start printing bold.

Note: The PRINT command simply scans the data for [Esc-G]. It does not know how the [Esc-G] sequence was generated. In most cases, the only way [Esc-G] is generated is via the @ function. However, if you are printing data that may contain [Esc-G], for example, graphical data, you should turn off the printer driver before printing your data. See DRIVER_CONTROL below to see how this is done.

Printer Tables

You can access and modify the tables that store the printer control codes through the Management-Hardware-Printer-Definitions menu.

Filling out the table, either to create a new printer definition or to modify an existing one, is a matter of putting the proper escape sequences in the proper locations. See your printer manual for the codes and format required.

Some of the prompts in the window bear special mention.

Initialize

In the Printer Control section of the window is a prompt labelled Initialize. The values entered here will be sent to the printer whenever the PRNINIT$ code is encountered.

Initialize is used to return the printer to a known state. Most programs that print to the printer start off by initializing the printer. The system does not automatically send the initialize code to the printer when the printer driver is activated. You must do this within your program or through the Printer Processes Open code and command. The one exception is the Merge processor, which will indeed issue a "printer initialize" sequence before beginning a print run.

Printer Processes

On the last page of the definition window are prompts for Printer Processes. There is a code and command sequence for opening the print process, and another for closing the printer process.

The Open print process is executed whenever the printer driver is activated. This occurs:

  • When that printer driver is selected.
  • At login.
  • When a PRINTPROC OPEN command is executed from TCL.
  • From a TCL first-level reset.

The Close print process, on the other hand, is executed:

  • When the printer driver is deselected (ie, when a new printer is selected)
  • At logoff.
  • When a PRINTPROC CLOSE is executed at TCL.

The processing that happens from the code and command can be anything you need. For example, you may wish to put your printer in landscape mode or you may want to execute the Initialize code automatically. Figure 1 is a program that can be used with any printer driver to execute the initialize code.

Prelude and End of Job

These prompts are intended to be used with PostScript printer drivers. The only printer driver shipped with Advanced Revelation that uses these prompts is the PostScript driver.

To use these prompts, you need to either write supporting routines or call PSSUBS and PSPRINT. PSSUBS controls the print process Open and Close features. PSPRINT formats the page and sends it to the printer.

Note: Do not make changes to the Prelude provided with the Advanced Revelation PostScript driver without first making a backup. For more information about the use of PSPRINT, see Technical Bulletin 99.

There are several ways to determine which printer driver is active. The preferred method is to use the system function GETCONFIGURE. Field 28 of the returned record is the name of the active printer, while Field 29 is a list of printers defined in the environment. The following code fragment shows how GETCONFIGURE is used.

DECLARE FUNCTION GETCONFIGURE
ERROR        = GETCONFIGURE(INF )
PRINTER_NAME = INFO<28>
PRINTERS     = INFO<29>

This will return (by name) the currently active printer, in the form of the record key to the table in the PRINTER_CONFIG file. The information returned by GETCONFIGURE is in part based on information maintained in @ENVIRON.SET. Field 92 of @ENVIRON.SET is a value mark-delimited list of printers. Field 93 is an associated list of printer ports.

The active printer can also be determined by calling SET_ACTIVE_PRINTER with a mode of 3. See below for details.

The active printer is usually changed by using the TCL command SETPRINTER or via the Environment menu options. Both methods present a popup of available printers (those currently in @ENVIRON.SET<92>) and let you to select the one to activate.

You may want to change the active printer driver from within a program. To do so, you must update fields 92 and 93 of @ENVIRON.SET and then call SET_ACTIVE_PRINTER with a mode of 1 and the ordinal number of the printer. See SET_ACTIVE_PRINTER below for details.

You can also control whether a printer driver is currently active. For example, if you are printing graphical data that may coincidentally contain escape sequences, you'll want to deactivate the printer driver first.

DRIVER_CONTROL is a system subroutine that controls whether the printer drivers are active. It takes one parameter, a code indicating what action to perform.

CodeAction
1Enable
2Disable
3Disable Video
4Disable Print
5Initialize
6Flush

1 - Enable

A code of 1 indicates that the printer drivers should be enabled. Enabling the drivers does not load the driver tables. It is assumed that the tables are already in memory.

2 - Disable

A code of 2 indicates that both the print and video drivers should be disabled. Disabling a driver does not remove the associated table from memory.

3 - Disable Video

A code of 3 indicates that only the video driver should be disabled. The printer driver remains active.

4 - Disable Print

A code of 4 indicates that the printer driver, but not the video, should be disabled. The printer driver should be disabled when you want to print data (for example, graphics) that may contain escape sequences that should not be interpreted by the driver.

5 - Initialize

A code of 5 indicates that the printer tables should be initialized. Both the display and the printer drivers for the last active printer are loaded from disk. To change which print driver gets loaded, use SET_ACTIVE_PRINTER, below.

6 - Flush

Use a code of 6 to flush the driver tables from memory. This is useful for freeing memory in tight memory conditions. You should disable the printer drivers when you flush the tables. When you are ready to use the drivers again, you must enable the drivers (using code 1) and load the driver tables (using code 5).

The following code fragments show how DRIVER_CONTROL can be used in your programs:

DECLARE SUBROUTINE DRIVER_CONTROL
EQU ENABLE$        TO 1
EQU DISABLE$       TO 2
EQU DISABLE_VID$   TO 3
EQU DISABLE_PRINT$ TO 4
EQU INIT$          TO 5
EQU FLUSH$         TO 6

DRIVER_CONTROL(DISABLE_PRINT$)
PRINT GRAPHICS_IMAGE
DRIVER_CONTROL(ENABLE$)

In this example the printer driver is turned off before printing a graphics image and then turned on after the image is printed.

* (initialization as above)
DRIVER_CONTROL(DISABLE$)
DRIVER_CONTROL(FLUSH$)
/* do processing */
DRIVER_CONTROL(ENABLE$)
DRIVER_CONTROL(INIT$)

This example shows how the drivers are turned off, and the tables flushed from memory and, after the memory intensive processing has completed, how the drivers are again enabled and loaded.

There is also a system subroutine to set the currently active printer. SET_ACTIVE_PRINTER lets you assign a new printer automatically or manually, and can be used to determine which printer is active. SET_ACTIVE_PRINTER takes three parameters: MODE, PRN_NUM, and STATUS.

MODE

MODE indicates the action to be performed. There are three modes:

ModeMeaning
1Automatic Selection
2Manual Selection
3Query

A MODE of 1 activates the printer specified in PRN_NUM.

A MODE of 2 displays a popup of available printer drivers. The value returned by the popup indicates the printer number to activate.

A MODE of 3 indicates that you want to find out which printer driver is active.

PRN_NUM

When MODE is 1, PRN_NUM is an integer indicating which printer driver to activate. The integer is the ordinal value of the printers in field 92 of @ENVIRON.SET. For example, if you pass PRN_NUM as 1, the first printer driver in field 92 of @ENVIRON.SET is activated.

When MODE is 3, PRN_NUM is returned as a two element dynamic array. Field 1 of the array is an integer representing the ordinal value of the current printer from those in field 92 of @ENVIRON.SET.

Note: If @ENVIRON.SET is changed after the printer driver is activated, PRN_NUM may not point to the name of the active printer; its value will only be updated during the next call to SET_ACTIVE_PRINTER. Do not rely on the position of PRN_NUM after you update @ENVIRON.SET.

Field 2 is a flag indicating whether the current printer has an Open code and command defined, and whether it has been executed.

STATUS

For all modes, STATUS is returned true if the operation succeeded, false otherwise.

The printer driver support in Advanced Revelation has spawned a certain number of questions. A sampling from the more common ones in Technical Support are addressed below.

How can I print in Landscape mode on a laser printer?

There are no explicit commands within the defined range of printer controls (e.g. BOLDON$, etc.) for orientation. However, you might try two strategies. The first is to use otherwise unused or little-used font controls as orientation control sequences. For example, you might define "Font 15" not to be a font at all, but to send to the printer the escape sequence required to switch to landscape, and "Font 16" as the sequence required for portrait mode.

Alternatively, you can define two different printer tables, one for portrait and another for landscape. In that case, to print in landscape mode, for example, you would choose the landscape version of the printer table.

You would need to be sure to download the appropriate orientation sequences to the printer when the printer driver is initialized, by either explicitly coding them into the "Open" code and command, or by embedding them as the Initialization code and making sure that this is downloaded to the printer when the printer is selected. (See "Printer Processes" under "Printer Tables", above.)

Can I control fonts in R/LIST, etc.?

As noted earlier, the most direct control over printers is via R/BASIC and to a lesser extent, from Merge. For other processes such as R/LIST you can establish a current printer, and all output will be sent in the default font characteristics of that printer. For example, if you choose a printer and then print an R/LIST report, the report will be sent appropriately to that printer, but will not otherwise (by default) allow any formatting of the data on the report.

Within certain limits, you can create symbolic dictionary items whose definition is simply the appropriate escape sequence, and then intersperse these "fields" in your report as required. For example, you might create (in the DICT of VOC) the fields BOLDON and BOLDOFF, whose definitions are, respectively:

/* BOLDON definition */
$INSERT INCLUDE, PRINT_CONSTANTS
@ANS = @(BOLDON$)
/* BOLDOFF definition */
$INSERT INCLUDE, PRINT_CONSTANTS
@ANS = @(BOLDOFF$)

This would let you to execute an R/LIST statement such as this one:

LIST SAMPLE_CUSTOMERS COMPANY_NAME BOLDON CITY BOLDOFF

The problem with this approach is the space required to "print" these two fields in the report. You must make the field at least four characters wide. When R/LIST formats the field, it will truncate it at the display length, not realizing that the contents of these particular fields are not meant to appear, just be used to control the printer. Truncating escape sequences before sending them to the printer results in unpredictable, and usually undesired, behavior. This truncation behavior is the norm for most output in the system (as, for example, in displaying such fields in an entry window), making it difficult to send printer or video control codes from within these higher-level processes.

Can I print using proportional typefaces?

It is quite possible to set up a proportional font such as Roman or Helvetica within the printer tables. However, Advanced Revelation continues to format using monospacing. For example, columns in R/LIST reports are aligned using embedded spaces. If you select a proportional font as the current font for your printer and then print an R/LIST (or other high-level) report, the columns will not align properly because of the varying widths of the characters in the report.

Can I have more than three printers available?

Yes. You can modify the PRINTER_SELECT window as described in Technical Bulletin #85, and change the row limit for that prompt.

This window simply updates the environment variable @ENVIRON.SET, although not immediately. You can therefore also update field 92 by adding printers (using @VM as a delimiter) to the list there, and adding the appropriate printer port information to field 93.

Can I control fonts in PostScript?

Yes. The PostScript driver supports, in addition to Courier, the fonts Times-Roman, New Century Schoolbook, and Helvetica. See the Postscript driver definition (in the Printer Definitions window) to see which @-codes activate which fonts. Be aware, however, of the limitations of using proportional typefaces (see above).

Changing the fonts supported by the PostScript driver entails changing the Prelude and is beyond the scope of this Technical Bulletin.

Figure 1

subroutine printinit

/* Call as the Print Process Open code and command: code - S command -
   PRINTINIT This program sends the PRNINIT$ code defined in the current
   printer driver to the printer.
*/

$insert include, print_constants

hold_printer = getprinter() ;* save off the curent state of the printer
printer on                  ;* turn the printer on
print @(prninit$):          ;* print the initialize code
printer off                 ;* turn the printer off
printer hold_printer        ;* return the printer to the way it was found
return
  • tips/revmedia/r100.txt
  • Last modified: 2024/06/19 20:20
  • by 127.0.0.1