Chapter 3 – A Word About Printing

 

Back in Chapter 1, we looked at some InternetBasic programs that displayed information on the screen in the IB window. In this chapter, we’ll take a look at programs that print information to printers and virtual printers. We’ll cover text output now, and save graphics output for a later chapter.

 

The IB runtime system refers to printers by 3-character names. You can configure as many printer names as you want, and there are only two rules:

 

 

Here are some sample printer names:

 

L01

L02

L03

L04

L10

L99

 

A popular approach is to use “LP” as the first part of the name, followed by a number or letter, such as:

 

LP1

LP2

LP3

LPH

LPT

 

Your printer names depend on the way you configure the IB runtime system (more on this topic later).

 

The compact disc that accompanies this book is configured with the following printer names:

 

LP1 – the Windows printer that is attached to your system

LPH – a “virtual” printer that displays IB output in your browser (in HTML format)

LPT – a “virtual” printer that displays IB output in your default text editor

 

Your IB program must open a printer before it can send output to it. Here’s how:

 

            OPEN (logical-unit-number) printer-name

 

The logical-unit-number is a number that identifies the printer throughout the program. The printer-name parameter is the 3-character name of the printer to be opened (e.g., LP1, LPH, LPT). Both of these parameters can be specified with variable names (a numeric variable for the logical-unit-number, and a string variable for the printer-name).

 

For example, here’s how to open LP1 using logical-unit-number 1:

 

            OPEN (1) "LP1"

 

Here’s how to use a variable for the printer-name:

 

LENGTH 3 & LOCAL PTR$               ! Define a variable

 

Print "Enter printer name:",@(0,3)   ! Display prompt

Input @(35,3),PTR$                  ! Input printer name

 

OPEN (1) PTR$                       ! Open printer

 

A logical-unit-number stays open until it is closed. This is done with the CLOSE statement:

 

            CLOSE (logical-unit-number)

 

In the above example, here’s how to close the printer:

 

            CLOSE (1)

 

A note about logical-unit-numbers

 

InternetBasic supports 50 logical-unit-numbers (luns), numbered from 0 to 49. Lun 0 serves a special purpose; it is the lun for the video screen of the IB client window. Luns 1 through 49 may be used for printers, data files, and other devices that can be opened by the IB program (such as gateway devices). There are no reserved luns above 0; values 1 through 49 are chosen by the programmer.

 

IB provides a simply way to check for errors that might occur when a program is running. All input/output statements, such as OPEN, may contain an additional clause that redirects the program to a specified statement label in the case of a runtime error (hereinafter called an exception). Here’s the syntax for the OPEN statement:

 

            OPEN (logical-unit-number) printer-name,EXCP=statement-label

 

Here’s an example:

 

            OPEN (1) "LP1",EXCP=ErrorRoutine

 

In English, this is:

 

Open the printer named LP1, using logical-unit-number 1. If a runtime exception occurs, branch to the ErrorRoutine statement label.

 

What could cause a runtime exception when a program tries to open a printer? There are a couple of common reasons. Most common is that the specified printer name is not configured (e.g., you try to open LP9, but that name does not exist in your IB configuration). Also, a printer is an exclusive device that can be opened by one program at a time. If your program tries to open a printer that’s already open (by another program or another IB user), your program will encounter a runtime exception.

 

There are specific error codes that your program can check in order to trap exceptions. We’ll cover these in Chapter 6. For now, the sample programs handle all runtime exceptions in a generic manner.

 

Once you’ve opened a printer, your program can print to it by using the lun in a PRINT statement. Here’s the syntax:

 

            PRINT (lun) print-item

 

For example:

 

            PRINT (1) "Customer History Report",@(0)

 

In English, this is:

 

Print the phrase “Customer History Report” on lun 1 (a printer that is open) starting at position 0 (i.e., the left-hand side of the page).

 

The PRINT statement may contain multiple print items, as long as a semicolon separates them. The syntax is:

 

            PRINT (lun) print-item;print-item;print-item

 

For example:

 

            PRINT (1) CUSTNUM$,@(0);NAME$,@(10);PHONE$,@(50)

 

In English, this is:

 

Print the value of the CUSTNUM$ variable starting a position 0, the value of NAME$ starting at position 10, and the value of PHONE$ starting at position 50.

 

Here’s a complete program that shows how to open, print to, and close a printer. This program is based on one of the samples from Chapter 1.

 

! //MTB// Src(SAMPLE7.MTB,BAS) Obj(SAMPLE7,BAS)

 

 

! Define the variables

 

      LENGTH 2.0

      LOCAL I

 

      LENGTH 16.2

      LOCAL AMOUNT

 

      LENGTH 3

      LOCAL PRINTER$

 

! Here's the code

 

      Print (CS)                    ! Clear the screen

 

      ! Display program information

 

      Print "If you start with 1 cent and double it every day,",@(0,0)

      Print "how much money will you have in 50 days?",@(0,1)

 

      ! Display a prompt, then input the response

 

      Print "Enter printer name for the output:",@(0,3)

      Input @(35,3),PRINTER$

 

      Open (1) PRINTER$,EXCP=OpenError    ! Open the printer

                                          !

                                          ! If there is an exception,

                                          ! branch to the OpenError

                                          ! statement label (below).

     

      Print (1) "Day",@(0);"Amount",@(21) ! Print the heading

 

      AMOUNT = .01                        ! Set the initial amount

 

      For I = 1 TO 50                     ! Loop from 1 to 50

        Print (1) I,@(0);AMOUNT,@(10)     ! Print the detail line

        AMOUNT = AMOUNT * 2               ! Double the amount

      Next I                              ! Loop

 

      Close (1)                           ! Close the printer

 

      ! Display ending message and use a "dummy INPUT" to hold it there

 

      Print "The printout is done.",@(0,5)

      GOTO Done

 

OpenError:

      Print "There was an error opening the printer.",@(0,5)

 

Done: Print "Press ENTER to continue...",@(0,7)

      Input @(30,7),""

STOP

 

END

 

As you can see, this program is named SAMPLE7 (source name is SAMPLE7.MTB). Run this program now and try printing to the virtual printer named LPH. The output is displayed in your web browser. (If you insist on using a piece of paper for the output, run the program again and choose LP1. Also, as long as you’re running this program, try printing to LPT, the virtual text printer.)

 

The next step is to make those large numbers look better. We’re going to add an edit mask to the output, so the large numbers will have commas between each group of 3 digits.

 

Since the AMOUNT variable is defined with a length and precision of 16.2, we’ll have to make an edit mask that matches it. Here’s what this looks like:

 

            ##,###,###,###,##0.00-

 

The digit positions are represented by # and 0, the commas represent group dividers, the decimal point serves its usual meaning, and the minus sign is the trailing character (not that this program is going to print any negative numbers, but a trailing character is required for all edit masks).

 

The # symbol in an edit mask tells IB to print blanks in place of leading zeroes. The 0 symbol tells IB to print the digit (zero or otherwise) starting in the position to the right of the first 0 in the edit mask. Thus, our sample edit mask always displays numbers to the right of the decimal point, but will print leading blanks up to and including the 1’s place.

 

See Chapter ??? for more information about edit masks.

 

When you use an edit mask, you must use a FORMAT statement. FORMAT statements must appear before the code section of the program, and (if they include variables) after the variables have been defined.

 

 

Data section

&

FORMAT statements

 

 

Code section

 

 

Here’s the syntax for a FORMAT statement:

 

            format-label FORMAT format-item(s)

 

The format-label identifies the FORMAT statement, but is not an executable statement label (in other words, you can’t GOTO a format-label). Since format-labels are not the same as executable statement-labels, you can use the same name in each section of the program (e.g., you could have a format-label of PRINTOUT and a executable statement-label of PRINTOUT in the same program).

 

Here’s a sample FORMAT statement:

 

            HEADING: FORMAT "Day",@(0);"Amount",@(25)

 

Note: A FORMAT statement is an inert object in an IB program. You “bring it to life” by using the appropriate input/output statement. For example:

 

            PRINT (1,HEADING)

 

As you can see, this is an alternate version of the PRINT statement. Instead of including print items on the same line as the PRINT statement, this PRINT refers to a FORMAT statement that contains those items.

 

Here’s the FORMAT statement for the detail lines in our sample program:

 

            DETAIL: FORMAT I,@(0);AMOUNT,@(10),"##,###,###,###,##0.00-"

 

Notice that the edit mask is the third parameter in the print item for the AMOUNT variable.

 

The associated PRINT statement is:

 

            PRINT (1,DETAIL)

 

Take a look at the sample program named SAMPLE8 (source name is XSAMPLE8) and you’ll see how the edit masks makes the large numbers look better.

 

Summary

 

While this chapter is short, it introduces some very important topics, including printer names, logical-unit-numbers, opening and closing a printer, dealing with runtime exceptions, printing to a printer (and virtual printer), using FORMAT statements, and edit masks. For the sake of simplicity, some details are missing from this chapter, but we’ll get to them soon enough.

 

In the next chapter, we’ll take a look at data files.