[comp.sys.hp] HP-UX, PostScript, LasetJetIII

richard@hpfcdc.HP.COM (Richard Artz) (01/29/91)

Steve writes:
 
>We just received a LasetJetIII and an HP PostScript
>Cartridge which I have a few questions on.
>1. What lp model should we use if the cartridge is
>installed? I have tried the HP-UX 7.0 laserjet model
>but the printer just hangs. If I cat to the print
>device however the postcript is printed properly.

7.0 shipped before HP had a cartridge so as far as I know there is
no PS script shipping with 7.0. But, you are on the right track, simply
take one of the 7.0 scripts and rip out everything except the line that
cat's the file. I've done this and it does work.

>2. We have some MacWrite II postscipt files that
>don't print. I've tried cat to the device and
>also sending them to a PSJet (LaserJet II with
>a hardware PostScript interface). Is this a
>problem with them not being encapsulated PostScript?

You didn't say if the printer acts (blinks) like it will print but
doesn't print. In that case, you may need a showpage at the end or
make sure that a CTRL-D ends the file.

>Thanks for any pointers..

Hope it helps

Richard Artz / OSSD Learning Products / 303-229-2036 / richard@hpfcww.fc.hp.com
 Hewlett-Packard / MS11 / 3404 E. Harmony Road / Fort Collins, CO 80525-9599 
This response does not represent the official position of, or statement by, the
Hewlett-Packard Company.  The above data is provided for informational purposes
only. It is supplied without warranty of any kind.

jco@reef.cis.ufl.edu (Dumpmaster John) (01/29/91)

In article <5570568@hpfcdc.HP.COM> richard@hpfcdc.HP.COM (Richard Artz) writes:
   take one of the 7.0 scripts and rip out everything except the line that
   cat's the file. I've done this and it does work.


You should also keep the stty line which sets up the port for you.

Here is a very primitive script for a ps model.  Something I've been meaning
to add is a cut line at the top to get the %! so that only PS files will
print.  Also a header would be nice.  :-)


later
jco

----------------------------Cut Here--------------------------------------
#!/bin/sh
# Author: John C. Orthoefer <jco@kzin.eel.ufl.edu>
# Date: 19 Dec 1990
# Based on the PCL level 4 HP printer model
#
# lp interface for HP laserjet IID w/ Hp Postscript cart.
#

seqid=$1
name=$2
title="$3"
copies=$4
options="$5"

# The remaining arguments are files
shift; shift; shift; shift; shift
files="$*"

stty raw 9600 -parenb cs8 ixon -istrip clocal <&1 2>/dev/null

# Print the spooled files

for file in $files
do
	cat "$file" 2>&1
	echo "\004\c"
done

stty raw 9600 -parenb cs8 ixon -istrip clocal <&1 2>/dev/null

exit 0


----------------------------Cut Here--------------------------------------
--
"BSD the strongest Operating System avaible today without a prescription."
In Real Life:		
John C. Orthoefer	Internet: jco@smuggler.cis.ufl.edu
University of Florida	Floyd Mailing List: eclipse-request@beach.cis.ufl.edu

tml@tik.vtt.fi (Tor Lillqvist) (01/30/91)

Here is the PS printer model I use.  

I2ps is an ASCII to PS (actually ISO Latin-1 to PS) filter.  Up is a
n-up PS filter. Both are written in Perl and were posted some time
ago.  I have included them too as an advertisement for Perl :-)

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Tor Lillqvist <tml@nyyti> on Wed Jan 30 10:47:58 1991
#
# This archive contains:
#	PS	i2ps	up	up.rc	
#
# Error checking via wc(1) will be performed.
# Error checking via sum(1) will be performed.

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH

if sum -r </dev/null >/dev/null 2>&1
then
	sumopt='-r'
else
	sumopt=''
fi

echo x - PS
cat >PS <<'@EOF'
# lp interface for PostScript printers connected via a tty port
#

PATH=/usr/local/bin:$PATH

baud=9600
copies=$4
stty $baud ixon igncr <&1
echo "\004\c"

shift; shift; shift; shift; shift

# The remaining arguments are files

files="$*"

# Print the spooled files

i=1
while [ $i -le $copies ]
do
	for file in $files
	do
		read word <$file
		case "$word" in
		%!*)	cat $file	# It is already PostScript
			;;
		*)	i2ps <$file | up # Print 2-up
			;;
		esac
	done
	i=`expr $i + 1`
done

echo '\004\c'

exit 0
@EOF
set `sum $sumopt <PS`; if test $1 -ne 29722
then
	echo ERROR: PS checksum is $1 should be 29722
fi
set `wc -lwc <PS`
if test $1$2$3 != 3787508
then
	echo ERROR: wc results of PS are $* should be 37 87 508
fi

chmod 755 PS

echo x - i2ps
cat >i2ps <<'@EOF'
#!/usr/local/bin/perl
'di';
'ig00';

# "i2ps" text to PostScript filter written in perl by Gisle Aas, NCC 1990
# $Id: i2ps,v 1.5 90/10/18 10:26:45 aas Exp $
#
# Whish list:  (this may become a feature some time)
#     Marking (by some funny char) truncation and wrapping of lines
#     Faster execution (rewrite the hole thing in C?)
#     Parsing of backspace to produce bold and underlined fonts.

#
# $Log:	i2ps,v $
# Revision 1.5  90/10/18  10:26:45  aas
# Changed the name from a2ps to i2ps. Merged the manual-page with the
# program. I2ps now rejects garbage files. I2ps was confused about what
# to put in the header when some of the specified files did not exist.
# Some minor spelling corrections.
# 
# Revision 1.4  90/10/01  15:57:46  aas
# Simplify reencoding to ISO-Latin1. (newencode)
# Fixed problem with showpage after page level restore. Graphic state
# initialized on each page. Included the ISOLatin1Encoding-vector
# in the script. Linenumber on last line when the -l option is used.
# Linenumbers are moved to the left margin.
# 
# Revision 1.3  90/09/27  14:05:31  aas
# Cleaned up the use of A4 variables.
# 
# Revision 1.2  90/09/27  13:18:31  aas
# Removed sccs-stuff, replaced it with rcs-stuff.
# 

# Some configuration constants, meassured in points (1/72 inch)
sub page_top        { 841; }    # A4 = 297mm x 210mm = 841pt x 595pt
sub page_right_edge { 595; }
# Uncomment next line if your printer doesn't have iso encoding builtin.
#$isoencoding_not_builtin = 1; #true

# The next few entries are from the AFM file for Adobe's font Courier
sub cour_char_width     { 600; }   # The width of each char in 1000x1000 square
#sub underline_position  { -82; }   # Where underline goes relative to baseline
#sub underline_thickness {  40; }   # and it's thickness

# Parse command line for options and flags
$prog = substr(__FILE__,rindex(__FILE__,"/")+1,999);
require 'getopts.pl';
unless (&Getopts('nfrth123s:b:lg')) {
   print STDERR "Usage: $prog [-<options>] [file]...\n";
   print STDERR "Options: -l       print with line numbers\n";
   print STDERR "         -r       rotated, landscape orientation\n";
   print STDERR "         -t       truncate long lines, " . 
                                  "default is to wrap lines\n";
   print STDERR "         -b\"text\" replaces the text in the page header\n";
   print STDERR "         -h       no page headers\n";
   print STDERR "         -2       set text in two columns format\n";
   print STDERR "         -3       set text in three columns format\n";
   print STDERR "         -s<size> select new text fontsize, default 10pt\n";
   print STDERR "         -g       don't reject garbage files\n";
   print STDERR "         -n       norwegian 7bit-ascii encoding\n";
   print STDERR "         -f       finnish/swedish 7bit-ascii encoding\n";
   exit(1);
}

# Set default values, some based on command line options
$left_margin  = 80;
$right_margin = 40;
$tb_margin    = 45;
$font         = "Courier";
$font_size    = 10;		$font_size = $opt_s if ($opt_s > 0);
$header_font  = "Helvetica-Bold";
$header_font_size = 12;
$line_number_font = "Helvetica";
$line_number_size = 5;

$line_height = $font_size * 1.08;
$no_columns = defined($opt_2) ? 2 : defined($opt_3) ? 3 : 1;
$col_separation = 30;
$sep_bars = 0;  # false
$landscape = defined($opt_r);
$header_height = 30;
$show_header = !defined($opt_h);
$wrap_lines = !defined($opt_t);
$truncate_lines = !$wrap_lines; # don't change this
$norsk_ascii = defined($opt_n);
$sw_fi_ascii = defined($opt_f);

# Some initial values
$opt_b = &ps_string($opt_b) if ($opt_b);
$form_feed = 0; # false;
$page_no  = 0;
$line_no = 0;
if ($landscape) {
    $top = &page_right_edge;
    $right_edge = &page_top;
    $left_margin = $right_margin; # this is a dirty one
} else {
    $top = &page_top;
    $right_edge = &page_right_edge;
}
$home_pos = $top - $tb_margin - ($show_header ? $header_height : 0);
$col_width = ($right_edge - $left_margin - $right_margin
              - ($no_columns - 1) * $col_separation) / $no_columns;
$char_width = &cour_char_width * $font_size / 1000;
$chars_per_line = int ($col_width / $char_width + 1);

&prolog;

unshift(@ARGV,'-') if $#ARGV < $[;
FILE:
while ($FILEHAND = shift) {
    unless (open(FILEHAND)) {
        print STDERR "Can't open \"$FILEHAND\"\n";
        next FILE;
    }
    if (!defined($opt_g) && -B FILEHAND) {
        print STDERR "Skipping binary file \"$FILEHAND\"\n";
        close(FILEHAND);
        next FILE;
    }
    $file_name = &ps_string($FILEHAND);
    $cur_pos = -1;     # this will force a new column next time
    $cur_col = 100;    # this will force a new page next time
    $line_no = 0;
    LINE:
    while (<FILEHAND>) {
        chop;
        $line_no++;
        if (ord == 014) {		# form feed
            s/.//;	# chop off first char
            $cur_pos = -1; 
            next LINE if (length == 0);
        }
        while (s/\t/' ' x (8 - length($`) % 8)/e) {}   # expand tabs
        do {
            if ($cur_pos < $tb_margin) {
                $cur_pos = $home_pos;
                if ($cur_col < $no_columns) {
                     $cur_col++;
                } else {
                     $cur_col = 1;
                     &new_page;
                }
            }
            $text = substr($_,0,$chars_per_line);
            $_ = $truncate_lines ? '' : substr($_,$chars_per_line,10000);
            if ($text =~ s/^ +//) {		# suppress leading blanks
                $indent = $char_width * length($&);
            } else {
                $indent = 0;
            }
            # Make suitable as a postscript string, same as calling
            # "ps_string", but the overhead of calling a function is
            # not acceptable here.
            $text =~ s/[\\\(\)]/\\$&/g;
            $text =~ s/[\000-\037\177-\377]/sprintf("\\%03o",ord($&))/ge;
            # Calculate position
            $x = $left_margin +
		 ($cur_col - 1) * ($col_width + $col_separation);
            $cur_pos -= $line_height;
            printf "(%s)%.1f %.1f S\n", $text, $x + $indent, $cur_pos 
                if (length($text));
            if ($opt_l && (($line_no % 5) == 0 || eof)) { # print line numbers
                 printf "F2 SF($line_no)%.1f %.1f S F1 SF\n",
                        $x + $col_width + 5, $cur_pos;
            }
        } while (length($_));
    } # while (each line)
} # while (each file)
&end_page;
print "%%Trailer\n";
print "%%Pages: $page_no\n";
# printf "($prog: $page_no page%s for $user\n) print\n",
#     $page_no != 1 ? "s" : "";

#--end of main-------------------------------------------------------


sub prolog {
   $user = getlogin || "(unknown)";
   local($sec,$min,$hour,$mday,$mon,$year) = localtime;
   $date = sprintf("(%s %d, %d) (%2d:%02d)",
                    ('January','February','March','April','May','June',
                     'July','August','October','November','Desember')[$mon],
                     $mday, $year+1900, $hour,$min);
   print "%!PS-Adobe-2.0\n";
   print "%%Title: @ARGV\n" if (@ARGV);
   print <<"EOT";
%%Creator: $prog, Text to PostScript filter in perl, (C) 1990 Gisle Aas, NCC
%%CreationDate: $date
%%For: $user
%%Pages: (atend)
EOT
   print "%%DocumentFonts: $font";
   print " $line_number_font" if ($opt_l);
   print " $header_font" if ($show_header);
   print "\n";
   print <<"EOT";
%%EndComments
/S{moveto show}bind def
/M/moveto load def
/L/lineto load def
/SF/setfont load def
EOT
    print <<"EOT" if ($isoencoding_not_builtin && !($norsk_ascii || $sw_fi_ascii));
ISOLatin1Encoding where { pop } { ISOLatin1Encoding
[/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright
/parenleft/parenright/asterisk/plus/comma/minus/period/slash/zero/one
/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal
/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S
/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum
/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s
/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/dotlessi/grave
/acute/circumflex/tilde/macron/breve/dotaccent/dieresis/.notdef/ring
/cedilla/.notdef/hungarumlaut/ogonek/caron/space/exclamdown/cent
/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine
/guillemotleft/logicalnot/hyphen/registered/macron/degree/plusminus
/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla
/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters
/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE
/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex
/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn
/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae
/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex
/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide
/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis]
def %ISOLatin1Encoding
} ifelse
EOT
    print <<"EOT" if ($norsk_ascii || $sw_fi_ascii);
%%BeginProcSet: reencode 1.0 0
/RE { %def
   findfont begin
   currentdict dup length dict begin
      { %forall
         1 index/FID ne {def} {pop pop} ifelse
      } forall
      /FontName exch def
      dup length 0 ne { %if
         /Encoding Encoding 256 array copy def
         0 exch { %forall
            dup type /nametype eq { %ifelse
               Encoding 2 index 2 index put
               pop 1 add
            }{%else
               exch pop
            } ifelse
         } forall
      } if pop
      currentdict dup
   end
   end
   /FontName get exch definefont pop
} bind def
%%EndProcSet: reencode 1.0 0
EOT
   print <<"EOT" if (!($norsk_ascii || $sw_fi_ascii));
%%BeginProcSet: newencode 1.0 0
/NE { %def
   findfont begin
      currentdict dup length dict begin
         { %forall
            1 index/FID ne {def} {pop pop} ifelse
         } forall
         /FontName exch def
         /Encoding exch def
         currentdict dup
      end
   end
   /FontName get exch definefont pop
} bind def
%%EndProcSet: newencode 1.0 0
EOT
   print "%%EndProlog\n%%BeginSetup\n";
   if ($norsk_ascii) {
      print "[8#133 /AE/Oslash/Aring 8#173 /ae/oslash/aring] dup\n";
      print "/$font-ISO/$font RE\n";
      print "/$header_font-ISO/$header_font RE\n" if ($show_header);
   } elsif ($sw_fi_ascii) {
      print "[8#133 /Adieresis/Odieresis/Aring
	      8#173 /adieresis/odieresis/aring] dup\n";
      print "/$font-ISO/$font RE\n";
      print "/$header_font-ISO/$header_font RE\n" if ($show_header);
   } else {
      print "ISOLatin1Encoding /$font-ISO/$font NE\n";
      print "ISOLatin1Encoding /$header_font-ISO/$header_font NE\n"
         if ($show_header);
   }
   print "/F1/$font-ISO findfont $font_size scalefont def\n";
   print "/F2/$line_number_font findfont $line_number_size scalefont def\n"
        if ($opt_l);
   print "/F3/$header_font-ISO findfont $header_font_size scalefont def\n"
        if ($show_header);
   print "F1 SF\n";
   print "%%EndSetup\n";
}



sub new_page {
   &end_page unless ($page_no == 0);
   $page_no++;
   print "%%Page: $page_no $page_no\n";
   print "%%BeginPageSetup\n";
   print "/page_save save def\n";
   printf "90 rotate 0 -%d translate %% landscape mode\n",&page_right_edge
      if ($landscape);
   print "0.15 setlinewidth\n" if ($show_header);
   print "%%EndPageSetup\n";
   if ($show_header) {
      # First print a box
      local($llx,$lly,$urx,$ury) = ($left_margin - 10,
            $top - $tb_margin - $header_font_size * 1.3,
            $right_edge - $right_margin + 10, $top - $tb_margin);
      printf "%.1f %.1f M %.1f %.1f L %.1f %.1f L ",
             $llx,$lly, $urx,$lly, $urx, $ury;
      printf "%.1f %.1f L closepath \n",$llx,$ury;
      print  "gsave .95 setgray fill grestore stroke\n";
      # Then the banner or the filename
      print "F3 SF\n";
      if ($opt_b) {
         printf "($opt_b)%.1f %.1f S\n",
                $left_margin,$top - $tb_margin - $header_font_size;
      }
      elsif ($file_name) {
         printf "(%s)%.1f %.1f S\n", $file_name, 
                      $left_margin,
                      $top - $tb_margin - $header_font_size;
      }
      # Then print page number
      printf "%.1f %.1f M($page_no)dup stringwidth pop neg 0 rmoveto show\n",
                 $right_edge - $right_margin, 
                 $top - $tb_margin - $header_font_size;
      print  "F1 SF\n";
   }
   if ($sep_bars) {
      print "% Some postscript code to draw horizontal bars.\n";
      print "% Not implemented yet\n";
   }
}

sub end_page {
   unless ($page_no == 0) {
      print "page_save restore\n";
      print "showpage\n";
   }
}

sub ps_string
{
   # Prepare text for printing
   local($_) = shift;
   s/[\\\(\)]/\\$&/g;
   s/[\001-\037\177-\377]/sprintf("\\%03o",ord($&))/ge;
   $_;    # return string
}


###########################################################################
	# These next few lines are legal in both Perl and nroff.

.00;			# finish .ig
 
'di			\" finish diversion--previous line must be blank
.nr nl 0-1		\" fake up transition to first page again
.nr % 0			\" start at page 1
';<<'.ex'; #__END__ #### From here on it's a standard manual page #########
.TH I2PS 1 "October 1990"
.SH NAME
i2ps \- convert ISO Latin1 text to PostScript
.SH SYNOPSIS
.B i2ps
[
.B \-nlrth23g
] [
.B \-b
.I "text"
] [
.B \-s
.I size
] [
.I filename
\&.\|.\|.
]
.SH DESCRIPTION
The
.B i2ps
program is used to print simple
text files (e.g. program listings) on a PostScript\*R device. 
The name
.B i2ps
stands for iso-to-postscript.  The program handles the whole
ISO Latin1 (ISO 8859/1) character set. 
Efforts have been made to ensure that 
.B i2ps
produces good looking and effective PostScript code.
The output conforms to Adobe's
document structuring conventions (version 2.1). The 
.B i2ps 
program
assumes that the page format on the output device is A4. 
(Change the definitions of &page_top and &page_right_edge if you
want something else.)
The meaning of form feed (^L) characters in the input stream is understood.
.PP
The
.B i2ps
program is written in
.I perl.
So if there is something you don't like about how
.B i2ps
works, you can "easily" fix it yourself.
.SH OPTIONS
.TP 5
.B \-n
use the norwegian version of ISO 646 (7-bit ascii) to encode the text.
Norwegian letters will replace the left/right braces, left/right
brackets, backslash and horizontal bar characters.
.TP 5
.B \-f
use the finnish/swedish of ISO 646.  Like 
.BR \-n ,
but instead of the AE ligature and slashed-O you get a and o with two dots.
.TP 5
.B \-l
produces line numbers on each 5'th and the last line.
Nice for program listings.
.TP 5
.B \-t
truncate lines that are to long. The default is to wrap
long lines so that they continue on the next line on the printed output.
.TP 5
.B \-r
rotate the output page 90 degrees. This is called
.I landscape
mode by some people.
.TP 5
.B \-h
suppress generation of page headers.
.TP 5
.B \-2
use two column format.
.TP 5
.B \-3
use three column format.
.TP 5
.BI \-b " text"
the 
.I text
parameter replaces the default text in the header of the pages.
The default text is the filename of the file to be printed. There is no
default if the text comes from standard input.
.TP 5
.BI \-s " size"
specifies a new font size for the body text. The default is 10 point.
.TP 5
.B \-g
eat garbage. 
.B I2ps 
normally skips binary files. This option means "print it anyway".
.SH EXAMPLES
To print files on a PostScript printer:
.nf
    i2ps -l *.[ch] | lpr
.fi
.PP
To find out how many pages i2ps will produce for a given file:
.nf
    i2ps file.txt | tail -1
.fi
.PP
Our printer stacks the pages the wrong way. To fix it try:
.nf
    cat file.txt | i2ps -b "some text" | psrev | lpr
.fi
.SH SEE ALSO
.BR perl (1),
.BR enscript (1),
.BR psrev (1),
.BR ISO8859 (7),
.BR PostScript (7)
.SH BUGS
There is no easy way to change the margins or the fonts that
.B i2ps
insists on using.
The
.B i2ps
filter ought to understand the meaning of the backspace character. It is used
to produce boldfaced and underlined text by programs like 
.BR nroff (1).
.SH AUTHOR
Gisle Aas, Norwegian Computing Center (NR), Oslo, Norway.
<Gisle.Aas@nr.no>
.ex
@EOF
set `sum $sumopt <i2ps`; if test $1 -ne 8224
then
	echo ERROR: i2ps checksum is $1 should be 8224
fi
set `wc -lwc <i2ps`
if test $1$2$3 != 502206916668
then
	echo ERROR: wc results of i2ps are $* should be 502 2069 16668
fi

chmod 555 i2ps

echo x - up
sed 's/^@//' >up <<'@EOF'
#!/usr/local/bin/perl
# up:
# PostScript n-up print utility.  This script takes conforming PS
# files, and prints them n-up, where n is controlled by a symbolic
# name (taken from argv[0] or the command line), and the page
# positioning and scaling are looked up in a configuration file.
#
# usage: up [-n name] [-f config] [file ...]
#
# jgreely@cis.ohio-state.edu, 89/10/23
#

# set the name from $0 (argv[0]), after stripping a path
#
@@foo = split(/\//,$0);
$name=pop(@foo);

$HOME=$ENV{"HOME"};

# set a default prolog in case the config file doesn't have one
# make sure that plines is 2 larger than the number of definitions in
# the prolog (used to get dictionary size).
#
$plines=10;
$prolog = <<EOF;
/inch {72 mul} def
/moveU {0 11 inch translate} def
/moveR {8.5 inch 0 translate} def
/moveD {0 -11 inch translate} def
/moveL {-8.5 inch 0 translate} def
/rotR {-90 rotate} def
/rotL {90 rotate} def
EOF

# search for a configuration file.  The *last* one found is used
#
$config = "./up.rc";
@@search_path = ("/usr/lib/up.rc","/usr/local/lib/up.rc","$HOME/.uprc",
                "./up.rc"); 
foreach $file (@search_path) {
	$config = $file if (-f $file && -r $file);
}

# check for options on command line.
#
while ($_ = $ARGV[0],/^-/) {
	shift;
	last if /^-\-$/;
	/^-[Ff]/ && ($config = shift,next);
	/^-[Nn]/ && ($name = shift,next);
	die "usage: up [-f config] [-n name] [file ...]\n";
}

# read relevant section of configuration file.	For complete format
# description, see the provided up.rc file or uprc(5).
#  Basically, read the config file until we find a line containing a
# name field equal to the current name.	 Once we do, read all name-
# value pairs up until a line containing just a '.', placing them all
# into an associative array.
#
open(config) ||
  die "can't find file '$config', stopped";
$in_rec = 0;
while(<config>) {
	chop;
	next if /^\s*#|^\s*$/;	# skip comment and blank lines
	if (/^prolog\s*=/) {
		do read_prolog();
		next;
	}
	next unless ($in_rec || /$name/);
	($field,$value) = split(/\s*=\s*/);
	if (($field eq "name") && ($value eq $name)) {
		$in_rec++;
		next;
	}
	last if /^\.$/;
	$var{$field} = $value;
}
close(config);
die "no such record '$name' in file '$config', stopped" unless $in_rec;
$modulus = $var{"modulus"};
die "invalid modulus == $modulus, stopped" unless $modulus;

$_ = <>;
if (/^%!PS-Adobe/) {
	print <<EOF;
%!PS-Adobe-2.0
%%Pages: (atend)
EOF
}else{
	die "Not conforming PostScript (no %!PS-Adobe), stopped";
}

# read comment section (up to first non-%% line, or %%EndComments)
#
while (<>) {
	if (!/^%%/) {
		do print_prologue();
		print;
		last;
	}
	if (/^%%EndComments/) {
		print;
		do print_prologue();
		last;
	}
	print;
}

while (<>) {
	#
	# to use slightly busted NeXT previewer
	#
	next if /^%%Pages:/;
	if (/^%%Page:/) {
		do enter_page();
		next;
	}
	if (/^%%Trailer/) {
		do print_trailer();
		next;
	}
	print;
}
# print actual page count.  This must be the last trailer comment
# printed.
#
print "%%Pages: $sheet\n";
exit(0);

# the prolog consists of simple command definitions you want to make
# available to the configuration routines.  None of them do anything
# complicated, but why make life more difficult for the user?
#
sub print_prologue {
	print <<EOF;
%%BeginProcSet: up_prolog 1 $$
/UpDict$$ $plines 3 add dict def
UpDict$$ begin
$prolog
/UpShowpage {showpage} bind def
/UpState {} def
end
/showpage {} def
%%EndProcSet: up_prolog 1 $$
EOF
}

# basically, at the beginning of a page, pull the number from the page
# header, take it modulo $modulus, and print things based on that #
# number.  If it's 1, end the previous sheet (if there is one),
# increment the sheet number, and print a sheet header.	 For all
# pages, print the appropriate page motion command.
#
sub enter_page {
	$page++;
	($foo,$bar,$oldpage) = split;
	die "Help! page number mismatch, stopped" if ($oldpage != $page);
	$temp = $page % $modulus;
	if ($temp == 1) {
		if ($sheet++) {
			print 
			  "UpDict$$ begin UpState restore UpShowpage end\n";
		}
		print <<EOF;
%%Page: ? $sheet
UpDict$$ begin
save /UpState exch def
EOF
		print $sheet % 2 ? $var{'odd'} : $var{'even'},"\n";
		print $var{"scale"},"\n";
	}else{
		print "UpDict$$ begin\n";
	}
	$temp = $modulus unless $temp;
	print $var{$temp},"\n";
	print "end\n";
}

# print the trailer, which for us consists of a showpage (inserted
# before the trailer comment, to make it part of the last page).
#
sub print_trailer {
	print "UpDict$$ begin UpState restore UpShowpage end\n" if $page;
	print "%%Trailer\n";
}

# read the prolog from the configuration file.	All lines up to the
# the first one starting with '.' will be placed in $prolog
#
sub read_prolog {
	$prolog='';
	#plines=0;
	while (<config>) {
		last if /^\./;
		$prolog .= $_;
		$plines++;
	}
	chop($prolog);
	$plines+=3;
}
@EOF
set `sum $sumopt <up`; if test $1 -ne 386
then
	echo ERROR: up checksum is $1 should be 386
fi
set `wc -lwc <up`
if test $1$2$3 != 2027714810
then
	echo ERROR: wc results of up are $* should be 202 771 4810
fi

chmod 755 up

echo x - up.rc
sed 's/^@//' >up.rc <<'@EOF'
# jgreely@cis.ohio-state.edu, 89/10/23
#

# this is the normal prolog, and defines everything used below
#
prolog=
/inch {72 mul} def
/mm {2.8346457 mul} def

statusdict begin printerstatus 126 and 2 eq end % test for A4
{ %ifelse
	/paperwidth 210 mm def
	/paperheight 297 mm def
} {
	/paperwidth 8.5 inch def
	/paperheight 11 inch def
} 
ifelse

/paperratio paperwidth paperheight div def

/moveU {0 paperheight translate} def
/moveR {paperwidth 0 translate} def
/moveD {0 paperheight neg translate} def
/moveL {paperwidth neg 0 translate} def
/rotR {-90 rotate} def
/rotL {90 rotate} def
/doSpiral {moveU moveR rotR 0.6667 dup scale} def
/moveHU { 0 paperheight 2 div translate} def
/doRevSpiral {moveHU rotL 0.6667 dup scale} def
@.

# up is a synonym for twoup, since my code doesn't work correctly for
# the case n==1.  Until I robustify it, this will stay.
#
name=up
modulus=2
scale=paperwidth 0 translate rotL paperratio dup scale
1=
2=moveR
@.

name=2up
modulus=2
scale=paperwidth 0 translate rotL paperratio dup scale
1=
2=moveR
@.

# two-up with even pages rotated, for double-siding
#
name=pup
modulus=2
even=moveU moveR rotR rotR
odd=
scale=paperwidth 0 translate rotL paperratio dup scale
1=
2=moveR
@.

# note that 4up is scaled a bit smaller than you might think.  If I
# just scaled by .5, I'd lose my top and bottom edges (printer
# limitations)
#
name=4up
modulus=4
scale=0.2125 inch 0.275 inch translate 0.475 dup scale
1=moveU
2=moveR
3=moveL moveD
4=moveR
@.

# this does a greeting-card format, designed to be folded into
# fourths.  If you're not sure how it's supposed to look, run:
#    makeup 4 | up -n card | lpr
#
name=card
modulus=4
scale=0.2125 inch 0.275 inch translate 0.475 dup scale
1=moveU moveU moveR rotR rotR
2=moveU moveU moveR rotR rotR
3=moveR
4=moveU moveU moveR rotR rotR
@.

# this is about the limit for a 300 dpi device, unless it's reasonably
# new and you have good eyes.  I like it at 400 dpi.
#
name=6up
modulus=6
scale=0.25 inch 0.75 inch translate rotL 4 11 div dup scale
1=moveD
2=moveR
3=moveR
4=moveD moveL moveL
5=moveR
6=moveR
@.

# this is a bit too far for casual reading.  It's entering magnifying
# glass territory, which is bad, unless you need to carry lots of RFCs
# around.
#
name=8up
modulus=8
scale=0.7 inch 0 translate rotL 11 34 div dup scale
1=moveD
2=moveR
3=moveR
4=moveR
5=moveD moveL moveL moveL
6=moveR
7=moveR
8=moveR
@.

# Steve Romig's contribution to evil PostScript hacking.  To see what
# it does, run:
#    makeup 10 | up -n spiral | lpr
#
name=spiral
modulus=10
scale=7.75 inch 0 translate rotL 11 17 div dup scale
1=
2=doSpiral
3=doSpiral
4=doSpiral
5=doSpiral
6=doSpiral
7=doSpiral
8=doSpiral
9=doSpiral
10=doSpiral
@.

# More from Steve, this time in the other direction
#
name=revspiral
modulus=10
scale=7.75 inch 0 translate rotL 11 17 div dup scale
1=moveR
2=doRevSpiral
3=doRevSpiral
4=doRevSpiral
5=doRevSpiral
6=doRevSpiral
7=doRevSpiral
8=doRevSpiral
9=doRevSpiral
10=doRevSpiral
@.

# this is not legible on anything under 400 dpi, and even then you'll
# probably want a magnifying glass.  You *can* read it with the naked
# eye, but not for long.
#
name=16up
modulus=16
scale=0.25 0.25 scale
1=moveU moveU moveU
2=moveR
3=moveR
4=moveR
5=moveD moveL moveL moveL
6=moveR
7=moveR
8=moveR
9=moveD moveL moveL moveL
10=moveR
11=moveR
12=moveR
13=moveD moveL moveL moveL
14=moveR
15=moveR
16=moveR
@.
@EOF
set `sum $sumopt <up.rc`; if test $1 -ne 18758
then
	echo ERROR: up.rc checksum is $1 should be 18758
fi
set `wc -lwc <up.rc`
if test $1$2$3 != 1775543380
then
	echo ERROR: wc results of up.rc are $* should be 177 554 3380
fi

chmod 644 up.rc

exit 0
--
Tor Lillqvist,
working, but not speaking, for the Technical Research Centre of Finland