#!/usr/bin/perl -w
use strict;
use Getopt::Std;
my $columns=1;
my $duplex=0;
my $landscape=0;
my $lineheight=10;
my $showlinenum=1;
my $tabwidth=8;
my $wrap=1;
my $pagetitle=undef;

my $helpstring="[-Ldhnw] [-clt <#>] [-P <printer>] [-T <title>] <files>";
my %opt=();
my $VERSION="1.3";
getopts("LP:T:c:dhl:nt:w",\%opt) or exit 1;
if($opt{h}) {
	print "usage: $0 $helpstring\n";
	print <<'EOD';
 -L      print in landscape mode
 -P <s>  print to printer queue <s> (i.e., using "lpr -P <s>")
 -T <s>  uses <s> as the title of the print job
 -c <#>  put text in <#> columns
 -d      print in duplex mode
 -h      shows this help message
 -l <#>  use <#> as the line height (in 1/72nds of an inch)
 -n      don't show line numbers
 -t <#>  set tab width to <#>
 -w      don't wrap lines
EOD
	exit(0);
}
$landscape=1 if($opt{L});
if($opt{c}) {
	die "invalid number of columns" unless($opt{c} =~ /^[1-9]\d*$/s);
	$columns=$opt{c};
}
$duplex=1 if($opt{d});
if($opt{l}) {
	die "invalid line height" unless($opt{l} =~ /^[1-9]\d*(?:\.\d+)?$/s);
	$lineheight=$opt{l};
}
if($opt{t}) {
	die "invalid tab width" unless($opt{t} =~ /^[1-9]\d*$/s);
	$tabwidth=$opt{t};
}
$showlinenum=0 if($opt{n});
$wrap=0 if($opt{w});
if(exists $opt{T}) {
	$pagetitle=$opt{T};
} else {
	$pagetitle=join(" ",@ARGV);
}
my $cmd="";
if(defined($opt{P})) {
	if($opt{P}) {
		$cmd="|lpr -P '$opt{P}'";
	} else {
		$cmd="|lpr";
	}
}

sub cvs {
	my ($string)=@_;
	$string =~ s/[()\\]/\\$&/gs;
	$string =~ s/\r/\\r/gs;
	return "($string)";
}

my $header=<<'EOD';
%!PS
/leftmargin   50 def
/rightmargin  40 def
/topmargin    50 def
/bottommargin 40 def
EOD
$header.="<</Duplex true>>setpagedevice\n" if($duplex);
$header.=<<'EOD';
currentpagedevice /PageSize get aload pop
EOD
$header.=($landscape?"true":"false");
$header.=<<'EOD';
 {
	exch
	dup 0 translate 90 rotate
} if
	/pageheight exch topmargin sub bottommargin sub def
	/pagewidth exch leftmargin sub rightmargin sub def
EOD
$header.="/pagetitle ".cvs($pagetitle)." def\n";
$header.="/lines [\n";
my $line;
while(defined($line=<>)) {
	if(defined($cmd)) {
		if($cmd) {
			open(STDOUT,$cmd) or die "lpr: $!";
		}
		print $header or die "write: $!";
		$header="";
		$cmd=undef;
	}
	chomp $line;
	while($line =~ s/^(.*?)\t//s) {
		$line=$1.(" "x($tabwidth-length($1)%$tabwidth)).$line;
	}
	print cvs($line)."\n" or die "write: $!";
}
exit(1) if(defined($cmd));
print "] def\n" or die "write: $!";
print "/columns $columns def\n" or die "write: $!";
print "/lineheight $lineheight def\n" or die "write: $!";
print "/wraplines ".($wrap?"true":"false")." def\n" or die "write: $!";
print <<'EOD' or die "write: $!";

/linenumstyle {
	/Times-Roman lineheight .9 mul selectfont
	.5 setgray
} bind def
/textstyle {
	/Courier lineheight selectfont
	0 setgray
} bind def
/pagenumstyle {
	/Times-Roman 10 selectfont
	0 setgray
} bind def
/charsperline pagewidth columns div textstyle (W) stringwidth pop div floor cvi def
/linespercolumn pageheight lineheight div floor cvi def

/totallines
	wraplines {
		0 lines {
			length 1 sub charsperline idiv 1 add
			dup 1 lt {pop 1} if
			add
		} forall
	} {
		lines length
	} ifelse def
/totalpages totallines linespercolumn columns mul div ceiling cvi def

/rshow {dup stringwidth neg exch neg exch 2 copy rmoveto 3 2 roll show rmoveto} bind def
EOD
print "/showlinenum ".($showlinenum?"true":"false")." {{\n" or die "write: $!";
print <<'EOD' or die "write: $!";
	gsave
	linenumstyle
	curx 5 sub cury moveto
	linenum 11 string cvs rshow
	grestore
}} {{}} ifelse bind def
/newpage {
	/pagenum pagenum 1 add def
	gsave
		pagenumstyle
		leftmargin pagewidth add 10 add bottommargin pageheight add 10 add moveto
		1 totalpages lt {
			totalpages 11 string cvs rshow
			( of ) rshow
			pagenum 11 string cvs rshow
			(page ) rshow
		} if
		pagetitle length 0 gt {
			1 totalpages lt {
				( - ) rshow
			} if
			pagetitle rshow
		} if
	grestore
} bind def
/movedown {
	/cury cury lineheight sub def
	cury bottommargin lt {
		/curcolumn curcolumn 1 add def
		curcolumn columns lt {
			/curx curx pagewidth columns div add def
		} {
			/curcolumn 0 def
			/curx leftmargin def
			showpage
			newpage
		} ifelse
		/cury pageheight bottommargin add lineheight sub def
	} if
} bind def

/linenum 0 def
/pagenum 0 def
/curcolumn 0 def
/curx leftmargin def
/cury pageheight bottommargin add def
totalpages 0 gt {newpage} if
textstyle
lines {
	/linenum linenum 1 add def
	movedown
	showlinenum
	{
		dup length charsperline le wraplines not or {
			curx cury moveto show exit
		} if
		dup 0 charsperline getinterval
		curx cury moveto show
		charsperline 1 index length charsperline sub getinterval
		movedown
	} loop
} forall
linenum 0 gt {showpage} if
EOD
close(STDOUT) or die "close: $!";
0;
