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.

About these ads

Pages: 1 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 576 other followers

%d bloggers like this: