[comp.lang.postscript] Debugged version of a2ps

cplai@daisy.UUCP (Chung-Pang Lai) (12/13/88)

This posting is a debugged version of a2ps script by Mr. Kirshenbaum of
Stanford.  His original was posted in May 88.  The original posting includes
4 different files: a invocation sh script, a .awk file, a .sed file and of
course the .ps PostScript prolog.  Four separate files introduce maintenance
problems.  When you move these around in your bin directories, if you miss one,
the whole thing fails.  Hence we merged all four files into one script.  No
more worries when you move it around!  Besides, there are bug fix and
performance enhancement.  If you like the original, you'd like this better.

I enjoy sharing what I know about PS, I hope someone will point out mistakes
that I made.  Code reviews lead to perfection! :-)

I might have missed later posting from Mr. Kirshenbaum.  The following
is based on his first original only.  If anyone has Mr. Kirshenbaum's
later enhancements, please e-mail me a copy.

> From: evan@csli.STANFORD.EDU (Evan Kirshenbaum)
> Subject: Ascii to PostScript conversion
> Date: 25 May 88 18:56:08 GMT
> Message-ID: <4052@csli.STANFORD.EDU>
> Organization: Center for the Study of Language and Information, Stanford U.

> Ok, folk, the initial response has been sufficient to warrant posting
> the code to the net.  
> To use, just say
>   	a2ps  file1 file2 ...
> This produces output suitable for piping through lpr to a PostScript
> printer. 

Since then, Mr. B.G. of U. of Colorado posted a bug fix to the PS code.

> From: csutest@sigi.Colorado.EDU (Test login per Dave )
> Subject: bug in a2ps utility
> Message-ID: <6504@sigi.Colorado.EDU>
> Date: 6 Jun 88 21:59:34 GMT
> Organization: University of Colorado, Boulder

> The bug symptom limits the number of pages to be printed
> to less than 10.  The reason is that the number-to-string conversion function
> (cvs) is trying to store too large of a source number into too small of a 
> destination string yielding a rangecheck error. The fix is to provide a large 
> enough buffer for the destination string as follows in the diff log:

> [ partial fix by B.G. deleted ]

> ----------------------------------------------------------------------------
> hope this is helpful,
> B.G.

B.G. caught one bug which occurs whenever the "page" number reaches 2 digits.  
He fixed the problem by placing a 
	/pstr 20 string def
in front of the statement
	/pnum pagenum pstr cvs def
inside the procedure /printheader.
This fix works, but have a problem.  Each time the /printheader procedure
is called, a string of 20 bytes is allocated.  If you are printing thousand of 
pages, gradually, the VM will be fragmented and totally consumed.

Furthermore, B.G. didn't catch another identical bug which aborts the printing 
whenever the "sheet" number reaches 2 digits.  We fixed that.

We also used the format   { } bind def    to force early name binding in all 
the procedures.  Supposedly, the binding will eliminate name lookups for the 
operators in the procedures when PS interpretes them.  And hence, a boost in 
performance.  We have not run any benchmark.  If anyone have time to compare
the speed of the two versions, please let me know the result.

--Cut-Here----Cut-Here----Cut-Here----Cut-Here----Cut-Here----Cut-Here--
#! /bin/sh
# File: csli:/user/evan/bin/a2ps
# Created: Wed May 25 11:32:18 1988 by evan@csli (Evan Kirshenbaum)
# Version: 1.0(1)
# Description: Convert files from ascii to PostScript.  
#              Usage:  a2ps file1 file2 ...
#              Writes to standard output (I generally pipe through
#              lpr). Files are prepared for printing landscape, two to
#              a page, boxed.  Header for each page has the format:
#                  Print-Time   File-Name  Page-Number
#              where page-number starts at 1 for each file.  Each
#              sheet in the batch is also numbered in the lower
#              right-hand corner.
#
#              Customizability will be included soon.  
#
#              Requires 'expand' (change tabs to spaces) in the search
#              path. 
#
# Edit History:
# 11/29/88	pkl@daisy	Changed to /bin/sh and rolled all
#				PS/awk/sed scripts into one shell 
#				for easier maintainence.

# Generate PostScript prologue
cat << !!END!!OF!!PS!!PROLOGUE!!
%!  PostScript Source Code
%  File: csli:/user/evan/bin/a2ps.ps
%  Created: Wed May 25 11:22:04 1988 by evan@csli (Evan Kirshenbaum)
%  Version: 1.0(1)
%  Description: PostScript prolog for a2ps ascii to PostScript program.
% 
%  Edit History:
%  11/29/88	cplai@daisy	added pnumbuf to allow printing of 
%				10 or more pages

/xdef {exch def} bind def
/inch {72 mul} bind def
/getfont {exch findfont exch scalefont} bind def

/filenamesize 12 def
/filenamefont /Helvetica-Bold filenamesize getfont def
/linesperpage 66 def

/datesize filenamesize 2 sub def
/datefont /Helvetica datesize getfont def
/headersize filenamesize 4 add def
/bodysize 6.8 def
/bodyfont /Courier bodysize getfont def
/sidemargin 4 def
/topmargin 4 def
/pagewidth 
   bodyfont setfont (0) stringwidth pop 80 mul sidemargin dup add add
   def
/pageheight
   bodysize linesperpage mul topmargin dup add add headersize add
   def
/uppery 8.5 inch pageheight add 2 div def
/upperx [ 11 inch pagewidth 2 mul sub 3 div
          dup 2 mul pagewidth add ] def

/pnumbuf 10 string def

/endpage
   { pageside 1 eq
       { /pageside 0 def
	 numberpage
         copypage erasepage 
	 /sheet sheet 1 add def }
       { /pageside 1 def }
     ifelse
     /pagenum pagenum 1 add def
    } bind def
/numberpage
    { 11 inch upperx 0 get sub sidemargin add
      8.5 inch uppery sub headersize sub moveto
      datefont setfont
      sheet pnumbuf cvs show
    } bind def
/newfile
    { /filename xdef
      /pagenum 1 def 
    } bind def
/cleanup
    { pageside 1 eq
      {numberpage showpage} if
    } bind def
/startdoc
    { 8.5 inch 0 inch translate
      90 rotate 
      /pageside 0 def
      /sheet 1 def
    } bind def
/startpage
    { printheader
      printborder
      upperx pageside get sidemargin add
      uppery topmargin sub bodysize sub headersize sub moveto
      bodyfont setfont
    } bind def
/s  { gsave
        show
      grestore
      0 bodysize neg rmoveto
    } bind def
/printheader
    { upperx pageside get uppery headersize sub 1 add moveto
      datefont setfont
      gsave
        sidemargin 2 rmoveto date show
      grestore
      gsave
	/pnum pagenum pnumbuf cvs def
        pagewidth sidemargin sub pnum stringwidth pop sub
        (Page ) stringwidth pop sub 3 rmoveto
        (Page ) show pnum show
      grestore
      gsave
        filenamefont setfont
        pagewidth filename stringwidth pop sub 2 div 2 rmoveto
        filename show
      grestore
    } bind def
/printborder 
    { upperx pageside get uppery moveto
      gsave
        pagewidth 0 rlineto
        0 pageheight neg rlineto
        pagewidth neg 0 rlineto
        closepath stroke
      grestore
      0 headersize neg rmoveto pagewidth 0 rlineto stroke
    } bind def
!!END!!OF!!PS!!PROLOGUE!!

# Define current date and time and start document
date +"/date (%d %h 19%y  %r) def"
echo "startdoc"

# Process each file on the command line, take standard input
# if there is no arguments on the command line
if [ $# -eq 0 ]; then
	list=-
else
	list="$*"
fi
for i in $list
do
	if [ $i = "-" ]; then
		echo "(stdin) newfile"
	else
		echo "($i) newfile"
	fi
	cat $i | expand | sed 's/[\\()]/\\&/g' \
	    | awk 'BEGIN		{ line=0; print "startpage" }
		(line>65 || $0~/^/)	{ line=0; print "endpage startpage" }
		$0~/^ *$/		{ next }
					{ print "(" $0 ") s"; line++ }
		END			{print "endpage"}'
done
echo "cleanup"
-- 
.signature under construction ...

{cbosgd,fortune,hplabs,seismo!ihnp4,ucbvax!hpda}!nsc!daisy!cplai    C.P. Lai
Daisy Systems Corp, 700B Middlefield Road, Mtn View CA 94039.  (415)960-6961