Printing Files
May 28, 2010
We assume 8½ × 11 inch paper at six lines per inch, for 66 lines per page. If you were writing a real program instead of an exercise, the page length would certainly be a parameter to the program, not a constant. With the margins below, there will be 60 lines of output on each page:
(define margin1 2) ; margin above the title line
(define margin2 1) ; margin between title line and print body
(define margin3 2) ; margin between body and end of page
(define pagelen 66) ; number of lines per page
(define bottom (- pagelen margin3)) ; last printable line
Skip
produces n blank lines; the version shown below prints an “X” at the beginning of each line, to make it easy to count lines during debugging:
(define (skip n)
(do ((n n (- n 1))) ((zero? n))
(display "X") (newline)))
The page header is output at two different points in the print program, so we make it a separate function. The page header consists of margin1
blank lines, followed by a line containing the file name and page number, followed by margin2
blank lines. You may wish to augment the title line with date-and-time or other information:
(define (head name pageno)
(skip margin1)
(display name)
(display " Page ")
(display pageno)
(newline)
(skip margin2))
We are following the text of Section 3.5 in the book Software Tools in Pascal by Brian W. Kernighan and P. J. Plauger (an oldie but goodie, that’s the book that taught me to program long ago). They give the following pseudocode for the function that prints a single file:
fprint(name, fin)
initialize
while (getline(line, fin, MAXSTR))
if (at top)
print page header
print line
if (page full)
space to bottom
if (page partially full)
space to bottom
We’ll honor Kernighan and Plauger by using the same logic and even the same variable names:
(define (print-file name)
(with-input-from-file name
(lambda ()
(let ((lineno (+ margin1 margin2 1)) (pageno 1))
(head name pageno)
(do ((line (read-line) (read-line))) ((eof-object? line))
(when (zero? lineno)
(set! pageno (+ pageno 1))
(head name pageno)
(set! lineno (+ margin1 margin2 1)))
(display line) (newline) (set! lineno (+ lineno 1))
(when (>= lineno bottom)
(skip (- pagelen lineno))
(set! lineno 0)))
(when (> lineno 0)
(skip (- pagelen lineno)))))))
All that’s left is to march through the list of file names:
(define (print-files . names)
(do ((names names (cdr names))) ((null? names))
(print-file (car names))))
There are many possible extensions; if you’re on a unix system, say man pr
for some ideas. We used read-line
from the Standard Prelude. You can see the code at http://programmingpraxis.codepad.org/kReRK3au.
I’d like to thank you for the efforts you’ve put in writing this website.
I really hope to check out the same high-grade content from you later on as well.
In fact, your creative writing abilities has encouraged me to get my
very own site now ;)