!lm10
!rm76
Screen Printers in One Line....................Bob Sander-Cederlof

When you are writing a fancy program to help you in your business, you spend a lot of time formatting the screen output.  You want it to look perfect!

But how do you get it from the screen to your printer?  You might end up re-writing the whole output routine, or incorporating a machine language screen dump.  You don't have to go to such extremes, because you can copy the contents of the screen to your printer with as little as one line of Applesoft code!

Here is one such line, printed with one statement per physical line for easy reading by humans.  (But it is still only one line to Applesoft.)

!lm15
100 PR# 1
    : FOR V = 1 TO 24
    :   FOR H = 1 TO 40
    :     VTAB V
    :     HTAB H
    :     VH = PEEK(40)+PEEK(41)*256+H-1
    :     CH = PEEK (CH)
    :     PRINT CHR$(CH+32*(CH<32));
    :   NEXT
    :   PRINT
    : NEXT
    : PR# 0
    : CALL 1002
    : RETURN

!lm10
Note that the RETURN on the end means I am expecting you to call this with a GOSUB 100.  If you want to, you can put this line right where you need it as in-line code, and leave off the RETURN.

How does it work?  First, PR#1 turns on your printer.  It also unhooks DOS, but we don't need DOS right now anyway.  We will rehook it at the end.  Look to the last few lines now:  PR#0 turns off your printer, and CALL 1002 re-hooks DOS.

The first FOR loop covers the 24 lines of the screen.  The second FOR loop covers the 40 characters of each line.  VTAB V and HTAB H position the cursor over the next character on the screen to be copied to your printer.  VTAB V also sets up locations 40 and 41 with the actual memory address of the first character on line V.  The "VH =" statement computes the memory address of character H on line V.

CH=PEEK(VH) will retrieve the character under the cursor.  PRINT CHR$(CH+32*(CH<32)) prints that character on your printer.  It also prints it on the screen, but so what?  Since we are printing the same character on top of itself, nothing changes.  That is, unless the character was INVERSE mode.  Inverse mode characters are converted to FLASH mode on the screen, and both of those modes are printed as NORMAL mode on the printer.  (Note that the expression 32*(CH<32) equals 0 if CH is greater than 31, and equals 32 if CH is less than 32.)
!np
NEXT : PRINT : NEXT moves us to the next character until the end of line, then prints a carriage return on the printer, and then moves us to the next line on the screen.  After all the lines have been printed, the printer is unhooked, DOS rehooked, and the subroutine returns.

Here is another version, which computes its own screen addresses in a series of three nested FOR loops:

!lm15
100 PR# 1
    : PRINT CHR$ (9)"80N"
    : FOR I = 0 TO 80 STEP 40
    :   FOR J = I+1024 TO I+1920 STEP 128
    :     FOR K = J TO J+39
    :       CH = PEEK(K)
    :       PRINT CHR$(CH+32*(CH<32));
    :     NEXT
    :     PRINT
    :   NEXT
    : NEXT
    : PR# 0
    : CALL 1002
    : RETURN

!lm10
Notice I had to print a control-I and "80N" to the printer interface to turn off the screen echo in this version.

It seemed to me that this second version ran a little faster than the first one, although I didn't use a stopwatch.  Both versions keep ahead of the printer anyway.
