/* -*-C-*- LPTOPS.C */
/*-->lptops*/
/**********************************************************************/
/******************************* lptops *******************************/
/**********************************************************************/

/***********************************************************************

NB: In order to handle overprinting of input of the form

...text...<CR>...overtext...<CR><LF>

this must be loaded with a special version of the C library I/O  routine
(PCC:IOCR.REL on the DEC-20) which permits reading and writing of  <CR>.
No special  action need  be taken  on Unix  systems, since  <CR> is  not
filtered out, and is normally absent.	On PC-DOS, open options of  "rb"
will usually  be necessary  (this  is the  default  on all  systems  but
TOPS-20).
***********************************************************************/

/***********************************************************************
	       Line printer file to PostScript converter
			      [03-Jul-85]
			      [12-Nov-85]
			      [07-Apr-86]
                              [03-May-88]

lptops converts normal text  files into PostScript  for printing on  the
Apple LaserWriter, or any  other PostScript-compatible printing  device.
It supports selection of  a variety of fonts  at arbitrary point  sizes,
margin specification, portrait and landscape page orientation, automatic
page numbering, page outlining, and multi-column printing.  It can  also
handle overstruck text used by many document formatters for underlining.

Usage:

	lptops [switches] <infile >outfile
	lptops [switches] filelist >outfile

In the switch descriptions below, physical dimensions described as # may
be specified as a single number with an optional fractional part, and  a
required two-letter unit designator.  Letter case is ignored.	Possible
forms are:

#.##bp  big point (1in = 72bp)	     [Courier: 120.000/Pbp cpi]
#.##cc  cicero (1cc = 12dd)	     [Courier:	 9.381/Pcc cpi]
#.##cm  centimeter		     [Courier:	 4.233/Pcm cpi]
#.##dd  didot point (1157dd = 1238pt)[Courier: 112.569/Pdd cpi]
#.##in  inch			     [Courier:	 1.667/Pin cpi]
#.##mm  millimeter (10mm = 1cm)      [Courier:  42.333/Pmm cpi]
#.##pc  pica (1pc = 12pt)	     [Courier:  10.038/Ppc cpi]
#.##pt  point (72.27pt = 1in)	     [Courier: 120.450/Ppt cpi]
#.##sp  scaled point (65536sp = 1pt) [Courier:	 7.893/(Psp/1000000) cpi]

The bracketed values give the number of characters per inch (cpi) for  a
point size of P units with  the fixed-width Courier font.  For  example,
with point size  8bp, there are  120/8 = 15  characters per inch.   With
point size 1000000sp, there are 7.893 characters/inch.

The optional switches are (letter case is ignored):

	-A	Turn Scribe-like bold and italic requests (@b[...] and
		@i[...]) into bold or italic text.

	-B#	Bottom margin of #.

	-Cn	Print n copies of each page.

	-Ffontname
		PostScript fontname.   Possible values  with  acceptable
		short abbreviations formed  from the upper-case  letters
		in the font names, and the ditroff and Adobe  TranScript
		abbreviations  are  as  follows.    The  first  13   are
		available on all PostScript printers; the remainder  are
		available only on enhanced  printers, such as the  Apple
		LaserWriter Plus.

		====================		=====	======	==========
		full name			short	ditroff	TranScript
		====================		=====	======	==========
		Courier				C	C	C
		Courier-Bold			CB	CB	CB
		Courier-BoldOblique		CBO	CD	CD
		Courier-Oblique			CO	CO	CO
		Helvetica			H	he	he
		Helvetica-Bold			HB	He	He
		Helvetica-BoldOblique		HBO	HE	HE
		Helvetica-Oblique		HO	hE	hE
		Symbol				S	S	S
		Times-Bold			TB	R	ti
		Times-BoldItalic		TBI	BI	TI
		Times-Italic			TI	I	tI
		Times-Roman			T	R	ti

		AvantGarde-Book			AGB	ag	ag
		AvantGarde-BookOblique		AGBO	aG	aG
		AvantGarde-Demi			AGD	Ag	Ag
		AvantGarde-DemiOblique		AGDO	AG	AG
		Bookman-Demi			BD	Bo	Bo
		Bookman-DemiItalic		BDI	BO	BO
		Bookman-Light			BL	bo	bo
		Bookman-LightItalic		BLI	bO	bO
		Helvetica-Narrow		HN	hn	hn
		Helvetica-Narrow-Bold		HNB	Hn	Hn
		Helvetica-Narrow-BoldOblique	HNBO	HN	HN
		Helvetica-Narrow-Oblique	HNO	hN	hN
		NewCenturySchlbk-Bold		NCSB	Nc	Nc
		NewCenturySchlbk-BoldItalic	NCSBI	NC	NC
		NewCenturySchlbk-Italic		NCSI	nC	nC
		NewCenturySchlbk-Roman		NCSR	nc	nc
		Palatino-Bold			PB	Pa	Pa
		Palatino-BoldItalic		PBI	PA	PA
		Palatino-Italic			PI	pA	pA
		Palatino-Roman			PR	pa	pa
		ZapfChancery-MediumItalic	ZCMI	ZC	ZC
		ZapfDingbats			ZD	ZD	ZD
		====================		=====	======	==========

		The ditroff and  TranScript  abbreviations are the same,
		except for the Courier and Times fonts.  They  are based
		on two-letter  mnemonics, where upper-case  in the first
		letter means bold, and upper-case  in the second  letter
		means italic.

		Only the Courier fonts  are fixed-width like  typewriter
		and line printer fonts are.  The others are proportional
		spaced  for  improved  readability,  and   consequently,
		tabular material will  not line up  properly with  them.
		The Courier fonts  have a  width equal to  0.6 of  their
		point size, so to fill a line W inches wide with up to N
		characters, one must have  point size <=  (W/(0.6 * N  *
		72)) = (W*120)/N pt.  Equivalently, with a point size  P
		pt, the output spacing is 120/P char/inch.

	-H	Horizontal page orientation (landscape mode) instead  of
		vertical page (portrait mode).

	-I#	Top margin of # for  initial page (for letterheads);  if
		not specified, it  will default to  the value given  for
		the top margin by default or by the -T# command.

	-L#	Left margin of #.

	-Mn	Multiple column output (n columns).  In multiple  column
		mode, formfeeds  cause  column breaks  instead  of  page
		breaks.

	-N[tb][lcr]n
		Number output pages.  The number is placed by default in
		the center  of the  top margin,  but the  margin can  be
		selected explicitly by  t (top) or  b (bottom), and  the
		position of the page number can be further specified  by
		l (left),  c (center),  or r  (right).  If  n is  given,
		start numbering with that  value, and otherwise with  1.
		If an initial  top margin  value is given  with the  -I#
		option, numbering will be omitted  on the first page  if
		it is at the top.   Pages are unnumbered if this  option
		is not specified.

	-O[#]	Outline pages  (and  columns) with  a  # units  wide.  A
		narrow line of 0.4pt width  is assumed if # is  omitted;
		this particular width is what TeX uses in typesetting.

	-P#	Font point  size  (default  10bp).   The  baseline  skip
		(spacing  between  successive  character  baselines)  is
		conventionally chosen to be 6/5  of this value, so  that
		with 10bp  type,  we  have  12bp  between  lines,  or  6
		lines/inch, the same as standard printer output.

	-R#	Right margin of #.

	-S[n]	special handling  (i.e. manual paper feed) for the first
		n pages  of the  output.  If  N multiple  copies are  in
		effect, then N*n sheets must  be fed manually.  If n  is
		omitted, then all  pages are  to be  fed manually.   For
		example, -S1 is convenient  to get the  first page of  a
		letter on letterhead paper fed manually, with  remaining
		pages from the paper cassette.

	-T#	Top margin of #.

	-U	Output pages in unsorted  (first to last) order  instead
		of in  sorted  (page reversed)  order;  some  PostScript
		printers have page handlers that stack the paper in this
		order.	 The   default  is   sorted  because   this   is
		appropriate for the most common PostScript printer,  the
		Apple LaserWriter.

Defaults are:

	-B1.0in -C1 -FCourier -L1.0in -M1 -P10bp -R1.0in -S0 -T1.0in


Revision history (reverse time order):

[03-May-88]	Add ditroff and Adobe TranScript font abbreviations.

[19-Apr-86]	Change page/line status report from output in End_Page()
		only to output in Beg_Page() and End_Column().

[07-Apr-86]	Fix some  incorrect  font  names, put  font  names  into
		table, add font abbreviations and new font names, change
		default font to Courier  (because most printing  expects
		fixed-width fonts).  Add usage  message if bad  options,
		and print  fontnames if  bad font  switch given.   Allow
		multiple filenames on command line instead of just using
		stdin -- this added  new function Do_File() and  changed
		argument  lists  of  inchar()  and  Copy_Plist().    Add
		save/restore around each page  image following new  1986
		PostScript Language Reference Manual recommendation, and
		change multiple  copies  sequence from  repeat  loop  to
		setting of standard variable #copies.  Add -U option for
		unsorted output.

[03-Feb-86]	Fix setting of final  entry of page_table[].  It  should
		only be done when End_Page() is called, since  otherwise
		Beg_Page() has already set the final entry, and we  just
		have an empty page to  be discarded.  Without this  fix,
		this left a hole (0), so  the entire file got copied  in
		its entirety to the last page of the sorted file.

[18-Jan-86]	Add (void) to fprintf()/printf(), test for disk  storage
		full at end  of page, add  OUTSTR() macro using  fputs()
		instead of fprintf() for efficiency.

[20-Dec-85]	Change getchar() to inchar(); the latter supplies a
		trailing LF at EOF in the event it is missing.
		Otherwise, the output PostScript has two tokens
		jammed together (P 1 {copypage} --> P1 {copypage})

[20-Dec-85]	Following recommendation of Allan Hetzel on LASER-LOVERS
		ARPA BBOARD, added "() pop" at top of every page.  This
		is selected by the switch FIX31OCT85:

		--------------------------------------------------------
		From: Allan Hetzel  <SYSAL%UKCC.BITNET@WISCVM.ARPA>
		Subject: Re: Apple Laserwriter XON/XOFF problem
		To:  <LASER-LOVERS@WASHINGTON.ARPA>

		The note  posted to  Laser-Lovers on  Oct 28  by  Joseph
		Goldstone of  Symbolics  Cambridge Research  Center  was
		helpful but I didn't try his suggested fix correctly and
		so I called Adobe.  They were very helpful (much more so
		than Apple) and explained the problem and how to  bypass
		it.

		My  apologies  to   Adobe  if  this   not  an	accurate
		description of the problem.   The problem apparently  is
		due to the  PostScript interpreter  getting confused  by
		what it thinks is an excess of white space characters.

		The bypass is to place a special character (parenthesis,
		bracket, brace, slash, etc.) to the right of some token,
		but without an intervening white space character. As the
		PostScript scanner  reads the  token it  also reads  the
		special character which acts as a delimiter. The scanner
		then has  to  back  up  one character  so  that  it  can
		reprocess the special character  after it has  processed
		the preceding token.  During  this backing up process  a
		number of  internal values  are recalculated,  including
		some pointer  into the  input buffer.	This causes  the
		XON/XOFF protocol to work properly.  Doing this once per
		page seems to keep everybody happy.

		Each page  in  the PostScript  file  built by  our  word
		processing program  is surrounded  by a  "save  restore"
		sequence.  We  changed	 the  beginning  save	sequence
		"/saveobj save def" to  read "/saveobj save def()  pop".
		The "() pop" is effectively  a no-op and we are  assured
		that the necessary recalculations are done on each page.
		This seems to have corrected the problem completely.

		Allan Hetzel (sysal@ukcc.bitnet)
		--------------------------------------------------------

[11-Dec-85]	Fix problem with extra () around overstruck text.

[13-Nov-85]	Insert FASTIO conditional compilation option to speed up
		page reversal.  Under VAX  4.2BSD, fread() and  fwrite()
		are already fast enough, and need not be replaced.

[12-Nov-85]	Add reversal of  pages, storing  output on  intermediate
		file which is deleted before exiting.

[02-Nov-85]	Add code to write output on temporary file, then
		retrieve in reverse page order and output on stdout.

[30-Oct-85]	Add code to handle overstruck lines:
		...text...<CR>...overtext...<CR><LF>
		will appear as
		(...text...) O
		(...overtext...) P

		Macro definitions and font selection now repeated
		on each page to allow selective reprinting.

[07-Oct-85]	Add code to discard input NUL's from word-padded files,
		since the LaserWriter prints them as blanks.

[27-Sep-85]	Added missing 'N' switch, fixed Page_Switch() (it scanned
		beyond last digit of page number)

[11-Jul-85]	Original version.


***********************************************************************/


#ifndef OS_TOPS20
#define OS_TOPS20	 0
#endif

#ifndef KCC_20
#define KCC_20		 0
#endif

#ifndef PCC_20
#define PCC_20		 0
#endif

#if    (KCC_20 | PCC_20)
#ifndef OS_TOPS20
#define OS_TOPS20	 1
#endif
#endif

#ifndef OS_VAXVMS
#define OS_VAXVMS	 0
#endif

#ifndef OS_ATARI
#define OS_ATARI	 0
#endif

#ifndef OS_PCDOS
#define OS_PCDOS	 0
#endif

#ifndef IBM_PC_AZTEC
#define IBM_PC_AZTEC	 0
#endif

#ifndef IBM_PC_LATTICE
#define IBM_PC_LATTICE	 0
#endif

#ifndef IBM_PC_MICROSOFT
#define IBM_PC_MICROSOFT 0
#endif

#ifndef IBM_PC_WIZARD
#define IBM_PC_WIZARD	 0
#endif

#if    (IBM_PC_AZTEC | IBM_PC_LATTICE | IBM_PC_MICROSOFT | IBM_PC_WIZARD)
#ifndef OS_PCDOS
#define OS_PCDOS	 1
#endif
#endif

#if    (OS_ATARI | OS_TOPS20 | OS_PCDOS | OS_VAXVMS)
#define OS_UNIX		 0
#else
#define OS_UNIX		 1
#endif

#if    (OS_ATARI | PCC_20)
#define DISKFULL(fp)	ferror(fp)	/* PCC-20 does not always set errno */
#else
#define DISKFULL(fp)	(ferror(fp) && (errno == ENOSPC))
#endif

#if    OS_VAXVMS
#define EXIT		vms_exit
#else
#define EXIT		exit
#endif

#if    IBM_PC_LATTICE
typedef int void;		/* Lattice C does not have this */
#endif

#if    IBM_PC_MICROSOFT
#define ANSI_PROTOTYPES		1
#endif

#ifndef ANSI_PROTOTYPES
#define ANSI_PROTOTYPES		0
#endif

#ifndef ANSI_LIBRARY
#define ANSI_LIBRARY		0
#endif

/*
************************************************************************
On  TOPS-20,   fread()/fwrite()   are  implemented   as   loops   around
getc()/putc() calls, and these in turn also do CR/LF translation.  Calls
to _read() and _write() translate into  direct calls to the Monitor  for
fast efficient block I/O.   FASTIO selects this option.   It is used  in
Copy_Block when the temporary  file is output in  reverse page order  to
stdout.
************************************************************************
*/

#if    OS_TOPS20
#if    PCC_20
#define FASTIO 1			/* TOPS-20 use only */
#undef DISKFULL
#define DISKFULL(fp)	ferror(fp)	/* PCC-20 does not always set errno */
extern	int strcmp();
#endif
#endif

#define FIX31OCT85 1			/* Allan Hetzel's XON/XOFF fix */

typedef int BOOLEAN;

#define FALSE 0
#define TRUE 1

#ifndef FASTIO
#define FASTIO		0
#endif

#define PXLID		0		/* used in inch.h */

#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>

#if    IBM_PC_MICROSOFT
/* int errno; */		/* not in errno.h */
#include <stdlib.h>
#include <time.h>
#endif

#if    OS_TOPS20
#include <time.h>
#endif

#if    FASTIO
#include <file.h>
#include <jsys.h>
#include <mon_s.h>
#endif

#if    (OS_TOPS20 | OS_UNIX | OS_VAXVMS | IBM_PC_AZTEC)
#define FOPEN_W "w"
#define FOPEN_R "r"
#else
#define FOPEN_W "wb"
#define FOPEN_R "rb"
#endif

/***********************************************************************
PostScript's basic units  are big  points (72bp =  1in).  Everything  in
this routine works in terms of "Quite Small Units": 1 inch = QSU qsu.
***********************************************************************/


#define NUL '\0'

#define QSU 100000L		/* quite small units per inch -- */
				/* should be large to avoid */
				/* truncation error accumulation */

#define INCH_TO_QSU(x) ((COORDINATE)(x * (float)QSU))
				/* inch to QSU conversion */

#define LEFT_X (left_margin + col_margin)
#define BOT_Y  (bottom_margin + col_margin)
#define TOP_Y(margin) (page_height - (margin) - baseline_skip - col_margin)

#if    OS_TOPS20	/* want <CR><LF> */
#define NEWLINE(fp) {(void)putc((char)'\r',fp);(void)putc((char)'\n',fp);}
#else
#define NEWLINE(fp) (void)putc((char)'\n',fp)	/* want bare <LF> */
#endif

#define OUTCHAR(c) (void)putc((char)(c),tf)
#define OUTOCTAL(c) (void)fprintf(tf,"\\%03o",(c))
#define OUTSTR(s) (void)fputs(s,tf)

#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))

#define HEIGHT (11L * QSU)	/* page height in QSU */
#define MAXBLOCK 4096L		/* block size for file copy */
#define MAXLEN 256		/* font name length */
#define MAXPAGE 1024		/* size of page location table */
#define WIDTH ((85L * QSU)/10L)	/* page width in QSU */
#define COL_TWIDDLE 40L		/* 1/fraction of column width for */
				/* column margin */

#define PAGE_T 001		/* flag bits for page_flag */
#define PAGE_B 002
#define PAGE_L 010
#define PAGE_R 020
#define PAGE_C 040

#define TEMPFILE "lptops.tmp"	/* temporary output file */


				/* global functions */
#if    ANSI_PROTOTYPES
int  main(int ,char *[]);
void Beg_Column(void);
void Beg_Line(void);
void Beg_Page(void);
void Beg_Text(char);
void Copy_Block(long ,long);
void Copy_Plist(char, FILE *);
void Do_File(FILE *);
void End_Column(void);
void End_Page(void);
void End_Line(void);
void End_Text(char);
float inch(char *);
int inchar(FILE *);
void Page_Switch(char *);

#if    ANSI_LIBRARY
int     atoi(const char *);
char*   ctime(const time_t *);
#else /* NOT ANSI_LIBRARY */
int     atoi(char *);
char*   ctime(long *);
#endif /* ANSI_LIBRARY */

char *cuserid(char *);
void EXIT(int);
char *getlogin(void);

#if    ANSI_LIBRARY
void perror(const char *);
char *strcpy(char *,const char *);
int strcm2(char *,char *);
size_t strlen(const char *);
char *strncpy(char *,const char *,size_t);
time_t time(time_t *);
int unlink(const char *);
#else /* NOT ANSI_LIBRARY */
void perror(char *);
char *strcpy(char *,char *);
int strcm2(char *,char *);
int strlen(char *);
char *strncpy(char *,char *,int);
long time(long *);
int unlink(char *);
#endif /* ANSI_LIBRARY */

#else
void Beg_Column();
void Beg_Line();
void Beg_Page();
void Beg_Text();
void Copy_Block();
void Copy_Plist();
void Do_File();
void End_Column();
void End_Page();
void End_Line();
void End_Text();
float inch();
int  inchar();
int  main();
void Page_Switch();

int  atoi();
char *ctime();
char *cuserid();
void EXIT();
char *getlogin();
void perror();
char *strcpy();
int  strcm2();
int  strlen();
char* strncpy();
long time();
int  unline();
#endif

typedef long COORDINATE;	/* variables in QSU need >=32 bits */


				/* global variables */

FILE *tf;			/* temporary output file */
BOOLEAN bad_option;		/* bad option flag */
COORDINATE baseline_skip;	/* inter-line spacing */
COORDINATE bottom_margin;	/* bottom margin width in QSU */
int  column;			/* current text column (1..numcol) */
COORDINATE col_margin;		/* column margin (extra space */
				/* between column borders in */
				/* multi-column mode) */
COORDINATE col_width;		/* column width in QSU */
int  copies;			/* number of copies of each page */
BOOLEAN  do_page_number;	/* page numbering flag */
char font_name[MAXLEN+1];	/* font name -- normal */
char font_bold[MAXLEN+1];	/* font name -- bold */
char font_italic[MAXLEN+1];	/* font name -- italic */
BOOLEAN found;			/* search flag */
int  in_col;			/* input line column */
int  init_page_number;		/* initial page number */
COORDINATE init_top_margin;	/* initial page top margin in QSU */
BOOLEAN landscape_mode;		/* horizontal landscape mode output */
COORDINATE left_margin;		/* left margin in QSU */
int  level;			/* parenthesis level */
int  line_number;		/* current line number */
int  manual_feed;		/* manual feed page count */
int  numcol;			/* number of text columns */
COORDINATE outline;		/* page and column outline linewidth */
int  page_flag;			/* page number location flag */
COORDINATE page_height;		/* page height in QSU */
int  page_number;		/* current page number */
long page_table[MAXPAGE+1];	/* page location table (with space */
				/* for extra entry marking EOF) */
COORDINATE page_width;		/* page width in QSU */
COORDINATE point_size;		/* font point size in big points */
BOOLEAN reverse;		/* page reversal flag */
COORDINATE right_margin;	/* right margin in QSU */
BOOLEAN scribe;			/* recognize bold/italic sequences */
COORDINATE top_margin;		/* top margin in QSU */
COORDINATE x;			/* current horizontal coordinate */
COORDINATE y;			/* current vertical coordinate */

/***********************************************************************
Built-in PostScript font tables.  The first column in each list contains
the full (case sensitive) PostScript  names, the second column  contains
convenient short abbreviations  which can  be used in  the command  line
-ffontname option,  the third  and fourth  columns contain  ditroff  and
Adobe TranScript abbreviations.

The  first  four  lines  of   entries  are  available  on  the   regular
LaserWriter, and the  remainder are  available only  on the  LaserWriter
Plus.
***********************************************************************/

char* ps_normal[] =
{
    /* fullname				short	ditroff	TranScript */
    "Courier",				"C",	"C",	"C",
    "Helvetica",			"H",	"he",	"he",
    "Times-Roman",			"T",	"R",	"ti",
    "Symbol",				"S",	"S",	"S",
    "AvantGarde-Book",			"AGB",	"ag",	"ag",
    "AvantGarde-Demi",			"AGD",	"Ag",	"Ag",
    "Bookman-Demi",			"BD",	"Bo",	"Bo",
    "Bookman-Light",			"BL",	"bo",	"bo",
    "Helvetica-Narrow",			"HN",	"hn",	"hn",
    "NewCenturySchlbk-Roman",		"NCSR",	"nc",	"nc",
    "Palatino-Roman",			"PR",	"pa",	"pa",
    "ZapfChancery-MediumItalic",	"ZCMI",	"ZC",	"ZC",
    "ZapfDingbats",			"ZD",	"ZD",	"ZD"
};

char* ps_bold[] =
{
    /* fullname				short	ditroff	TranScript */
    "Courier-Bold",			"CB",	"CB",	"CB",
    "Helvetica-Bold",			"HB",	"He",	"He",
    "Times-Bold",			"TB",	"B",	"Ti",
    "Symbol",				"S",	"S",	"S",
    "AvantGarde-Book",			"AGB",	"ag",	"ag",
    "AvantGarde-Demi",			"AGD",	"Ag",	"Ag",
    "Bookman-Demi",			"BD",	"Bo",	"Bo",
    "Bookman-Light",			"BL",	"bo",	"bo",
    "Helvetica-Narrow-Bold",		"HNB",	"Hn",	"Hn",
    "NewCenturySchlbk-Bold",		"NCSB",	"Nc",	"Nc",
    "Palatino-Bold",			"PB",	"Pa",	"Pa",
    "ZapfChancery-MediumItalic",	"ZCMI",	"ZC",	"ZC",
    "ZapfDingbats",			"ZD",	"ZD",	"ZD"
};

char* ps_italic[] =
{
    /* fullname				short	ditroff	TranScript */
    "Courier-Oblique",			"CO",	"CO",	"CO",
    "Helvetica-Oblique",		"HO",	"hE",	"hE",
    "Times-Italic",			"TI",	"I",	"tI",
    "Symbol",				"S",	"S",	"S",
    "AvantGarde-BookOblique",		"AGBO",	"aG",	"aG",
    "AvantGarde-DemiOblique",		"AGDO",	"AG",	"AG",
    "Bookman-DemiItalic",		"BDI",	"BO",	"BO",
    "Bookman-LightItalic",		"BLI",	"bO",	"bO",
    "Helvetica-Narrow-Oblique",		"HNO",	"hN",	"hN",
    "NewCenturySchlbk-Italic",		"NCSI",	"nC",	"nC",
    "Palatino-Italic",			"PI",	"pA",	"pA",
    "ZapfChancery-MediumItalic",	"ZCMI",	"ZC",	"ZC",
    "ZapfDingbats",			"ZD",	"ZD",	"ZD"
};

char* ps_both[] =
{
    /* fullname				short	ditroff	TranScript */
    "Courier-BoldOblique",		"CBO",	"CD",	"CD",
    "Helvetica-BoldOblique",		"HBO",	"HE",	"HE",
    "Times-BoldItalic",			"TBI",	"BI",	"TI",
    "Symbol",				"S",	"S",	"S",
    "AvantGarde-BookOblique",		"AGBO",	"aG",	"aG",
    "AvantGarde-DemiOblique",		"AGDO",	"AG",	"AG",
    "Bookman-DemiItalic",		"BDI",	"BO",	"BO",
    "Bookman-LightItalic",		"BLI",	"bO",	"bO",
    "Helvetica-Narrow-BoldOblique",	"HNBO",	"HN",	"HN",
    "NewCenturySchlbk-BoldItalic",	"NCSBI","NC",	"NC",
    "Palatino-BoldItalic",		"PBI",	"PA",	"PA",
    "ZapfChancery-MediumItalic",	"ZCMI",	"ZC",	"ZC",
    "ZapfDingbats",			"ZD",	"ZD",	"ZD"
};


#define PS_DEFAULT 0	/* index of default font in ps_normal[] */
#define MAXFONT (sizeof(ps_normal)/sizeof(char *)) /* size of font table */


int
main(argc,argv)
int argc;
char* argv[];
{
    register int k;			/* loop index */
    register char *p;			/* temporary pointer */
    register int m,n;			/* loop indices */
    FILE *fp;				/* input file pointer */
    char timestr[27];			/* result of ctime() */
    long timeval;			/* result of time() */
    long last,next;			/* result of fseek() for */
					/* page_table[] construction */
    int (*compare)();

    /* establish defaults for all parameters */
    bottom_margin = 1L * QSU;
    column = 1;
    col_margin = 0L;
    copies = 1;
    do_page_number = FALSE;
    init_page_number = 1;
    init_top_margin = -1;	/* negative value flags unset state */
    in_col = 0;
    landscape_mode = FALSE;
    left_margin = 1L * QSU;
    manual_feed = 0;
    numcol = 1;
    outline = 0L;
    page_height = HEIGHT;
    page_number = init_page_number;
    page_width = WIDTH;
    point_size = INCH_TO_QSU(inch("10bp"));
    reverse = TRUE;
    right_margin = 1L * QSU;
    scribe = FALSE;
    top_margin = 1L * QSU;

    strcpy(font_name,ps_normal[PS_DEFAULT]);
    strcpy(font_bold,ps_bold[PS_DEFAULT]);
    strcpy(font_italic,ps_italic[PS_DEFAULT]);

    bad_option = FALSE;
    for (k = 1; k < argc; ++k)
    {
	p = argv[k];
	if (argv[k][0] == '-')
	{
	    switch(argv[k][1])
	    {
	    case 'a':
	    case 'A':
		scribe = TRUE;
		break;

	    case 'b':
	    case 'B':
		bottom_margin = INCH_TO_QSU(inch(&argv[k][2]));
		break;

	    case 'c':
	    case 'C':
		copies = atoi(&argv[k][2]);
		break;

	    case 'f':
	    case 'F':
		(void)strncpy(font_name,&argv[k][2],MAXLEN);
		font_name[MAXLEN] = '\0';
		found = FALSE;
		for (n = 0; n < MAXFONT; n += 4)
		{
		    for (m = 3; m >= 0; --m)
		    {
			/* compare case-sensitive ditroff and TranScript
			   names before case-insensitive ones */
			compare = (m > 1) ? strcmp : strcm2;
			if ((*compare)(font_name,ps_normal[n+m]) == 0)
			{
			    strcpy(font_name,ps_normal[n]);
			    strcpy(font_bold,ps_bold[n]);
			    strcpy(font_italic,ps_italic[n]);
			    found = TRUE;
			    break;
			}
			else if ((*compare)(font_name,ps_bold[n+m]) == 0)
			{
			    strcpy(font_name,ps_bold[n]);
			    strcpy(font_bold,ps_bold[n]);
			    strcpy(font_italic,ps_italic[n]);
			    found = TRUE;
			    break;
			}
			else if ((*compare)(font_name,ps_italic[n+m]) == 0)
			{
			    strcpy(font_name,ps_italic[n]);
			    strcpy(font_bold,ps_both[n]);
			    strcpy(font_italic,ps_normal[n]);
			    found = TRUE;
			    break;
			}
			else if ((*compare)(font_name,ps_both[n+m]) == 0)
			{
			    strcpy(font_name,ps_both[n]);
			    strcpy(font_bold,ps_italic[n]);
			    strcpy(font_italic,ps_normal[n]);
			    found = TRUE;
			    break;
			}
		    }
		}
		if (!found)
		{
		    NEWLINE(stderr);
    		    (void)fprintf(stderr,
			"?Illegal font name [%s].  Possible values are:",
			font_name);
		    NEWLINE(stderr);

		    NEWLINE(stderr);
		    (void)fprintf(stderr,"Normal fonts");
		    NEWLINE(stderr);
		    for (m = 0; m < MAXFONT; m += 4)
		    {
			(void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s",
			    ps_normal[m],ps_normal[m+1],ps_normal[m+2],
			    ps_normal[m+3]);
			NEWLINE(stderr);
		    }

		    NEWLINE(stderr);
		    (void)fprintf(stderr,"Bold fonts");
		    NEWLINE(stderr);
		    for (m = 0; m < MAXFONT; m += 4)
		    {
			(void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s",
			    ps_bold[m],ps_bold[m+1],ps_bold[m+2],
			    ps_bold[m+3]);
			NEWLINE(stderr);
		    }

		    NEWLINE(stderr);
		    (void)fprintf(stderr,"Oblique/Italic fonts");
		    NEWLINE(stderr);
		    for (m = 0; m < MAXFONT; m += 4)
		    {
			(void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s",
			    ps_italic[m],ps_italic[m+1],ps_italic[m+2],
			    ps_italic[m+3]);
			NEWLINE(stderr);
		    }

		    NEWLINE(stderr);
		    (void)fprintf(stderr,"BoldOblique/BoldItalic fonts");
		    NEWLINE(stderr);
		    for (m = 0; m < MAXFONT; m += 4)
		    {
			(void)fprintf(stderr,"\t%-30s %-10s %-10s %-10s",
			    ps_both[m],ps_both[m+1],ps_both[m+2],
			    ps_both[m+3]);
			NEWLINE(stderr);
		    }
		    NEWLINE(stderr);
		    bad_option = TRUE;
		}
		break;

	    case 'h':
	    case 'H':
		landscape_mode = TRUE;
		break;

	    case 'i':
	    case 'I':
		init_top_margin = INCH_TO_QSU(inch(&argv[k][2]));
		break;

	    case 'l':
	    case 'L':
		left_margin = INCH_TO_QSU(inch(&argv[k][2]));
		break;

	    case 'm':
	    case 'M':
		numcol = atoi(&argv[k][2]);
		break;

	    case 'n':
	    case 'N':
		Page_Switch(&argv[k][1]);
		break;

	    case 'o':
	    case 'O':
		if (argv[k][2])		/* have -O# */
		    outline = INCH_TO_QSU(inch(&argv[k][2]));
		else			/* have -O, so give default */
		    outline = INCH_TO_QSU(inch("0.4pt"));  /* from TeX */
		break;

	    case 'p':
	    case 'P':
		point_size = INCH_TO_QSU(inch(&argv[k][2]));
		break;

	    case 'r':
	    case 'R':
		right_margin = INCH_TO_QSU(inch(&argv[k][2]));
		break;

	    case 's':
	    case 'S':
		if (argv[k][2]) /* have count field */
		    manual_feed = atoi(&argv[k][2]);
		else		/* omitted count ==> large number */
		    manual_feed = 32767;
		break;

	    case 't':
	    case 'T':
		top_margin = INCH_TO_QSU(inch(&argv[k][2]));
		break;

	    case 'u':
	    case 'U':
		reverse = FALSE;
		break;

	    default:
		NEWLINE(stderr);
		(void)fprintf(stderr,"?Unrecognized option [%s]",p);
		NEWLINE(stderr);
		bad_option = TRUE;
	    }
	}
    }

    if (bad_option)
    {
	(void)fprintf(stderr,
	    "Usage: %s -A -B# -Cn -Ffontname -H -I# -L# -Mn -N[tb][lcr]n \
-O[#] -P# -R# -S[n] -T# -U filelist >outfile",argv[0]);
	NEWLINE(stderr);

	(void)fprintf(stderr,"Default options: -B1.0in -C1 -FCourier -L1.0in \
-M1 -P10bp -R1.0in -S0 -T1.0in");
	NEWLINE(stderr);

	EXIT(1);
    }


    if (reverse)
    {
	if ((tf = fopen(TEMPFILE,FOPEN_W)) == (FILE *)NULL)
	{
	    NEWLINE(stderr);
	    (void)fprintf(stderr,"?Cannot open temporary file [%s]",TEMPFILE);
	    NEWLINE(stderr);
	    (void)perror("?perror() says");
	    EXIT(1);
	}
    }
    else
	tf = stdout;

    /*******************************************************************
    Make the PostScript File Structure header according to Version  1.0,
    First Edition  (January 1985)  of  the PostScript  File  Structuring
    Conventions manual.  We add  one additional field  at the end  after
    the %%Pages: n field:

    %%PageTable: m1 n1 p1 ... mk nk pk

    where the triples (mj  nj pj) contain the  page number pair (mj  nj)
    like the field

    %%Page: mj nj

    and pj is the  byte position in  the file of  the beginning of  that
    "%%Page" command.  A spooler can  then easily position to  arbitrary
    pages in the file for reprinting.
    *******************************************************************/

    OUTSTR("%!PS-Adobe-1.0");		/* magical file header */
    NEWLINE(tf);

    OUTSTR("%%DocumentFonts: ");
    OUTSTR(font_name);			/* only use one font */
    NEWLINE(tf);

    OUTSTR("%%Dimensions: 0 0 612 792");	/* 8.5 x 11 inch page size */
    NEWLINE(tf);

    OUTSTR("%%Title:");			/* this contains our command line */
    for (k = 0; k < argc; ++k)
    {
	OUTCHAR(' ');
	OUTSTR(argv[k]);
    }
    NEWLINE(tf);		       /* end of %%Title line */

    timeval = time((long *)NULL);
    strcpy(timestr,ctime(&timeval));
    k = strlen(timestr) - 1;	/* ctime has its own \n */
    timestr[k] = NUL;		/* so kill it */
    OUTSTR("%%CreationDate: ");
    OUTSTR(timestr);
    NEWLINE(tf);

    /* Under TOPS-20, JSYS GFUST% cannot be used to obtain file owner string
    of a terminal file, which stdout always is, so just use job login name */

    OUTSTR("%%Creator: ");
    if (cuserid((char*)NULL) != (char*)NULL)
        OUTSTR(cuserid((char*)NULL));
    NEWLINE(tf);

    OUTSTR("%%Pages: (atend)");
    NEWLINE(tf);
    OUTSTR("%%EndComments");
    NEWLINE(tf);
    OUTSTR("save");			/* has matching "restore" at end */
    NEWLINE(tf);
    OUTSTR("%%EndProlog");
    NEWLINE(tf);

		     /* validate input settings */
    copies = MAX(1,copies);
    numcol = MAX(1,numcol);
    point_size = MAX(INCH_TO_QSU(inch("3bp")),point_size);
    if (point_size > INCH_TO_QSU(0.25))
    {
	NEWLINE(stderr);
	(void)fprintf(stderr,
	    "%warning -- font point size > 18pt is unusually large!");
	NEWLINE(stderr);
    }
    outline = MAX(0L,outline);

    if (landscape_mode)		/* switch sizes for landscape mode */
    {
	page_height = WIDTH;
	page_width = HEIGHT;
    }
    if (((left_margin + right_margin) >= page_width) ||
	((top_margin + bottom_margin) >= page_height) ||
	((init_top_margin + bottom_margin) >= page_height))
    {
	NEWLINE(stderr);
	(void)fprintf(stderr,"?Margin values too large for page");
	NEWLINE(stderr);
	EXIT(1);
    }

    col_width = (page_width - left_margin - right_margin)/numcol;
    col_margin = ((numcol == 1) && (outline == 0)) ?
	0L : (col_width/COL_TWIDDLE);

    /* TeX's baselineskip is 12pt for 10pt type; we preserve the same ratio */
    baseline_skip = (point_size * 12L) / 10L;

    m = 0;				/* count of file names */
    for (k = 1; k < argc; ++k)
    {
	if (*argv[k] != '-')
	{
	    m++;			/* count file name */
	    if ((fp = fopen(argv[k],FOPEN_R)) != (FILE *)NULL)
	    {
		Do_File(fp);
		(void)fclose(fp);
	    }
	    else
	    {
		(void)fprintf(stderr,"?Open failure on [%s] -- file skipped",
		    argv[k]);
		NEWLINE(stderr);
	    }
	}
    }
    if (m == 0)
	Do_File(stdin);

    if (reverse)
    {
	/* Now close the temporary file and reopen for input, then transfer */
	/* complete pages in reverse order to stdout using large blocks */

	if (fclose(tf))
	{
	    NEWLINE(stderr);
	    (void)fprintf(stderr,"?Close failure on temporary file [%s]",
		TEMPFILE);
	    NEWLINE(stderr);
	    (void)perror("?perror() says");
	    EXIT(1);
	}

	if ((tf = fopen(TEMPFILE,FOPEN_R)) == (FILE *)NULL)
	{
	    NEWLINE(stderr);
	    (void)fprintf(stderr,"?Cannot reopen temporary file [%s]",TEMPFILE);
	    NEWLINE(stderr);
	    (void)perror("?perror() says");
	    EXIT(1);
	}

	NEWLINE(stderr);
	(void)fprintf(stderr,"[Reversing pages");
	Copy_Block(0L,page_table[0]-1);	/* first page is file header stuff */
	last = page_table[MIN(MAXPAGE,page_number-init_page_number+1)];
	for (k = MIN(MAXPAGE,page_number-init_page_number+1)-1; k >= 0; --k)
	{				/* copy remainder in reverse order */
	    (void)putc('.',stderr);
	    next = (long)ftell(stdout);
	    Copy_Block(page_table[k],last-1);
	    last = page_table[k];
	    page_table[k] = next;
	}
	(void)putc(']',stderr);
	if (fclose(tf))
	{
	    NEWLINE(stderr);
	    (void)fprintf(stderr,"?Close failure on temporary file [%s]",
		TEMPFILE);
	    NEWLINE(stderr);
	    (void)perror("?perror() says");
	    EXIT(1);
	}

	unlink(TEMPFILE);		/* delete the temporary file */
    }
    /* add file trailer stuff */

    tf = stdout;			/* so OUTSTR() macro works */

    OUTSTR("%%Trailer");
    NEWLINE(stdout);
    OUTSTR("restore");			/* matches "save" in prolog */
    NEWLINE(stdout);
    (void)printf("%%%%Pages: %d",page_number-init_page_number);
    NEWLINE(stdout);
    OUTSTR("%%PageTable: ");
    for (k = 0; k < MIN(MAXPAGE,page_number-init_page_number+1); ++k)
	(void)printf(" %d %d %ld",init_page_number+k,init_page_number+k,
	    page_table[k]);
    NEWLINE(stdout);
    if (putchar('\004') == EOF)		/* CTL-D for EOF signal */
    {
	NEWLINE(stderr);
	(void)fprintf(stderr,"?Output error -- disk storage probably full");
	NEWLINE(stderr);
	(void)perror("?perror() says");
	EXIT(1);
    }
    (void)fprintf(stderr," [ok]");
    NEWLINE(stderr);
    EXIT(0);
    return (0);				/* keep lint and compilers happy */
}

void
Beg_Column()
{
    (void)fprintf(tf,"%ld %ld moveto",x,y);
    NEWLINE(tf);
}

void
Beg_Line()
{
    if (scribe)
    {
	OUTCHAR('S');
	OUTCHAR(' ');
    }
}

void
Beg_Page()
{
    int k;

    column = 1;
    (void)fflush(tf);
    k = page_number-init_page_number;
    if (k < MAXPAGE)
	page_table[k] = (long)ftell(tf);
    (void)fprintf(tf,"%%%%Page: %d %d",k+1,page_number);
    NEWLINE(tf);
    OUTSTR("save");	/* will be matched by "restore" from End_Page() */
    NEWLINE(tf);
    if (scribe)
    {
	(void)fprintf(tf,"/B {/%s findfont %ld scalefont setfont} def",
	    font_bold,point_size);
	NEWLINE(tf);

	(void)fprintf(tf,"/E {grestore 0 %ld rmoveto} def",
	    -baseline_skip);		/* End of line */
	NEWLINE(tf);

	(void)fprintf(tf,"/I {/%s findfont %ld scalefont setfont} def",
	    font_italic,point_size);
	NEWLINE(tf);

	(void)fprintf(tf,"/N {/%s findfont %ld scalefont setfont} def",
	    font_name,point_size);
	NEWLINE(tf);

	OUTSTR("/O {gsave show grestore} def");	/* OverPrint macro */
	NEWLINE(tf);

	OUTSTR("/S {gsave} def");	/* Start of line */
	NEWLINE(tf);

	OUTSTR("/W {show} def");	/* show text */
	NEWLINE(tf);
    }
    else
    {
	OUTSTR("/O {gsave show grestore} def");	/* OverPrint macro */
	NEWLINE(tf);

	(void)fprintf(tf,"/P {gsave show grestore 0 %ld rmoveto} def",
	    -baseline_skip);  /* Print macro */
	NEWLINE(tf);

	(void)fprintf(tf,"/N {/%s findfont %ld scalefont setfont} def",
	    font_name,point_size);
	NEWLINE(tf);
    }
    (void)fprintf(tf,"72 %ld div 72 %ld div scale",QSU,QSU);
    NEWLINE(tf);
    OUTCHAR('N');			/* select normal font */

#if    FIX31OCT85
    OUTSTR("()pop");			/* no-op for XON/XOFF bug workaround */
#endif

    NEWLINE(tf);

    if (landscape_mode)
    {
	(void)fprintf(tf,"%ld %ld translate",0L,HEIGHT);
	NEWLINE(tf);
	OUTSTR("-90 rotate");
	NEWLINE(tf);
    }
    (void)fprintf(stderr,
	" [%d",page_number);	/* begin [p.l.l...] status report */
}

void
Beg_Text(c)
char c;
{
    if (c)
    {
	OUTCHAR(' ');
	OUTCHAR(c);
	OUTCHAR(' ');
    }
    OUTCHAR('(');
    level++;
}

void
Copy_Block(b1,b2)	/* copy bytes b1..b2 from tf to stdout */
long b1,b2;				/* start,end byte positions */
{
    static char block[MAXBLOCK];	/* static to save stack space */
    long k;				/* loop index */
    long length;			/* number of bytes to copy */

#if    FASTIO
    (void)fflush(stdout);		/* empty any buffered output */
#endif
    for (k = b1; k <= b2; k += MAXBLOCK)
    {
	length = MIN(MAXBLOCK,b2-k+1);

	(void)fseek(tf,k,0);		/* position to desired block */

#if    FASTIO
	if (_read(jfnof(fileno(tf)),block,(int)length) != (int)length)
#else
	if (fread(block,1,(int)length,tf) != (int)length)
#endif
	{
	    NEWLINE(stderr);
	    (void)fprintf(stderr,
	      "?Input block length error on temporary file [%s]",TEMPFILE);
	    NEWLINE(stderr);
	    (void)perror("?perror() says");
	    EXIT(1);
	}
#if    FASTIO
	if (_write(jfnof(fileno(stdout)),block,(int)length) != (int)length)
#else
	if (fwrite(block,1,(int)length,stdout) != (int)length)
#endif
	{
	    NEWLINE(stderr);
	    (void)fprintf(stderr,
	      "?Output block length error on stdout");
	    NEWLINE(stderr);
	    (void)perror("?perror() says");
	    EXIT(1);
	}
    }
    (void)fflush(stdout);
}

void
Copy_Plist(fontc,fp)		/* copy parenthesized list to tf */
char fontc;
FILE *fp;
{
    static char p_open[] = {'(','[','<','{',NUL};
    static char p_close[] = {')',']','>','}',NUL};
    register int match;
    register int c;

    c = inchar(fp);
    match = 0;
    while (p_open[match] && (p_open[match] != (char)c))
	match++;

    if (!p_open[match])
    {
	NEWLINE(stderr);
	(void)fprintf(stderr,"?@b or @i not followed by open parenthesis!");
	NEWLINE(stderr);
	EXIT(1);
    }

    Beg_Text(fontc);
    while (((c = inchar(fp)) != EOF) && ((char)c != p_close[match]))
    {
	if (c < ' ')
	{
	    NEWLINE(stderr);
	    (void)fprintf(stderr,
		"?@b[...] or @i[...] contains control character!");
	    NEWLINE(stderr);
	    EXIT(1);
	}
	in_col++;
	switch(c)
	{
	case '(':
	    OUTCHAR('\\');
	    OUTCHAR(c);
	    break;

	case ')':
	    OUTCHAR('\\');
	    OUTCHAR(c);
	    break;

	case '\\':
	    OUTCHAR('\\');
	    OUTCHAR(c);
	    break;

	default:
	    OUTCHAR(c);
	    break;
	}
    }
    End_Text('N');
    OUTCHAR(' ');
}

void
Do_File(fp)
FILE *fp;
{
    register int c;			/* character */

/**********************************************************************/
/*		       PostScript Output Section		      */
/**********************************************************************/

    x = LEFT_X;
    if (init_top_margin > 0)
	y = TOP_Y(init_top_margin);
    else
	y = TOP_Y(top_margin);

    Beg_Page();
    Beg_Column();
    level = 0;
    in_col = 0;
    line_number = 1;

    if ((c = inchar(fp)) != '\f')	 /* discard any initial FF */
	(void)ungetc(c,fp);

    while ((c = inchar(fp)) != EOF)
    {
	switch (c)
	{
	case NUL:
	    break;	/* discard NUL's from word-padded files */

	case '\b':
	    if (in_col > 0)
	    {
		in_col--;
		OUTCHAR('\\');
		OUTCHAR('b');
	    }
	    break;

	case '\f':
	    in_col = 0;
	    End_Text(NUL);
	    NEWLINE(tf);
	    End_Column();
	    if (column > numcol)
		Beg_Page();
	    Beg_Column();
	    line_number = 1;
	    break;

	case '\n':
	    line_number++;
	    if (in_col == 0)
	    {
		Beg_Line();
		Beg_Text(NUL);
	    }
	    End_Text(NUL);
	    End_Line();
	    in_col = 0;
	    y -= baseline_skip;
	    if (y < BOT_Y)
	    {
		End_Column();
		if (column > numcol)
		    Beg_Page();
		Beg_Column();
		line_number = 1;
	    }
	    break;


	case '\r':	/* check for special case of overprinting */
	    if ((c = inchar(fp)) != '\n') /* peek ahead one character */
	    {			/* and if not LF, have overstrike */
		while (level > 0)
		{
		    OUTCHAR(')');
		    level--;
		}
		in_col = 0;
		OUTCHAR('O');
		NEWLINE(tf);	/* this lines up under previous line */
	    }
	    (void)ungetc(c,fp);  /* put back the peeked-at character */
	    break;

	case '\t':
	    if (in_col == 0)
	    {
		Beg_Line();
		Beg_Text(NUL);
	    }
	    do
	    {
		in_col++;
		OUTCHAR(' ');
	    }
	    while (in_col & 07); /* blank fill to multiple of 8 columns */
	    break;

	case '(':
	    if (in_col == 0)
	    {
		Beg_Line();
		Beg_Text(NUL);
	    }
	    in_col++;
	    OUTCHAR('\\');
	    OUTCHAR('(');
	    break;

	case ')':
	    if (in_col == 0)
	    {
		Beg_Line();
		Beg_Text(NUL);
	    }
	    in_col++;
	    OUTCHAR('\\');
	    OUTCHAR(')');
	    break;

	case '\\':
	    if (in_col == 0)
	    {
		Beg_Line();
		Beg_Text(NUL);
	    }
	    in_col++;
	    OUTCHAR('\\');
	    OUTCHAR('\\');
	    break;

	case '@':
	    if (scribe)
	    {
		c = inchar(fp);
		if ((c == 'b') || (c == 'B'))
		{
		    if (in_col == 0)
			Beg_Line();
		    else
    			End_Text(NUL);
		    Copy_Plist('B',fp);
		    Beg_Text(NUL);
		    break;
		}
		else if ((c == 'i') || (c == 'I'))
		{
		    if (in_col == 0)
			Beg_Line();
		    else
    			End_Text(NUL);
		    Copy_Plist('I',fp);
		    Beg_Text(NUL);
		    break;
		}
		(void)ungetc(c,fp);	/* put back the peeked-at character */
		c = (int)'@';		/* and restore original character */
	    }
	    /* ELSE fall through to default! */

	default:
	    if (in_col == 0)
	    {
		Beg_Line();
		Beg_Text(NUL);
	    }
	    in_col++;
	    if ((c < 040) || (0176 < c))
		OUTOCTAL(c);
	    else
		OUTCHAR(c);
	    break;
	}
    }
    if (in_col > 0)
	End_Line();
    End_Text(NUL);
    column = numcol;			/* to force End_Page() action */
    End_Column();

    /* Normally, Beg_Page() sets the page_table[] entry.  Since this  is
    the last output  for this file,  we must set  it here manually.   If
    more files are  printed, this  entry will be  overwritten (with  the
    same value) at the next call to Beg_Page(). */
    page_table[page_number-init_page_number] = (long)ftell(tf);
}

void
End_Column()
{
    if (outline > 0)
    {
	NEWLINE(tf);
	OUTSTR("gsave");
	NEWLINE(tf);
	(void)fprintf(tf,"%ld setlinewidth",outline);
	NEWLINE(tf);
	(void)fprintf(tf,"newpath %ld %ld moveto",x - col_margin,bottom_margin);
	(void)fprintf(tf,
	    " %ld %ld rlineto %ld %ld rlineto %ld %ld rlineto closepath stroke",
	    col_width,0,
	    0,page_height-bottom_margin-top_margin,
	    -col_width,0);
	NEWLINE(tf);
	OUTSTR("grestore");
	NEWLINE(tf);
    }
    (void)fprintf(stderr,
	".%d",line_number);	/* continue [p.l.l...] status report */
    if (++column > numcol)	/* columns filled, so start new page */
    {
	(void)putc(']',stderr);	/* close [p.l.l...] report */
	End_Page();
    }
    else			/* just start new column */
    {
	x += col_width;
	y = TOP_Y(top_margin);
    }
}

void
End_Page()
{
    register int k;

    if (do_page_number)
    {
	if ((init_top_margin > 0) && (page_number == init_page_number)
	    && (page_flag | PAGE_T))
	    ;			/* omit leading top pagenumber */
	else
	    switch (page_flag)
	    {
	    case (PAGE_T | PAGE_L):
		NEWLINE(tf);
		(void)fprintf(tf,"%ld %ld moveto",left_margin,
		    page_height-top_margin/2-baseline_skip/2);
		(void)fprintf(tf," (%d) show",page_number);
		break;

	    case (PAGE_T | PAGE_C):
		NEWLINE(tf);
		(void)fprintf(tf,"%ld %ld moveto",page_width/2,
		    page_height-top_margin/2-baseline_skip/2);
		(void)fprintf(tf,
		    " (- %d -) stringwidth pop 2 div neg 0 rmoveto",
		    page_number);
		(void)fprintf(tf," (- %d -) show",page_number);
		NEWLINE(tf);
		break;

	    case (PAGE_T | PAGE_R):
		NEWLINE(tf);
		(void)fprintf(tf,"%ld %ld moveto",page_width-left_margin,
		    page_height-top_margin/2-baseline_skip/2);
		(void)fprintf(tf," (%d) stringwidth pop neg 0 rmoveto",
		    page_number);
		(void)fprintf(tf," (%d) show",page_number);
		NEWLINE(tf);
		break;

	    case (PAGE_B | PAGE_L):
		NEWLINE(tf);
		(void)fprintf(tf,"%ld %ld moveto",left_margin,
		    bottom_margin/2-baseline_skip/2);
		(void)fprintf(tf," (%d) show",page_number);
		break;

	    case (PAGE_B | PAGE_C):
		NEWLINE(tf);
		(void)fprintf(tf,"%ld %ld moveto",page_width/2,
		    bottom_margin/2-baseline_skip/2);
		(void)fprintf(tf,
		    " (- %d -) stringwidth pop 2 div neg 0 rmoveto",
		    page_number);
		(void)fprintf(tf," (- %d -) show",page_number);
		NEWLINE(tf);
		break;

	    case (PAGE_B | PAGE_R):
		NEWLINE(tf);
		(void)fprintf(tf,"%ld %ld moveto",page_width-left_margin,
		    bottom_margin/2-baseline_skip/2);
		(void)fprintf(tf," (%d) stringwidth pop neg 0 rmoveto",
		    page_number);
		(void)fprintf(tf," (%d) show",page_number);
		NEWLINE(tf);
		break;

	    default:			/* else no numbering */
		break;
	    }
    }
    page_number++;

    if (manual_feed > 0)
    {
	OUTSTR("statusdict begin");
	NEWLINE(tf);
	OUTSTR("statusdict /manualfeed true put");
	NEWLINE(tf);
    }

    if ((fprintf(tf,"/#copies %d def showpage",copies) == EOF) ||
	DISKFULL(tf))
    {
	NEWLINE(stderr);
	(void)fprintf(stderr,"?Output error -- disk storage probably full");
	NEWLINE(stderr);
	(void)perror("?perror() says");
	EXIT(1);
    }
    NEWLINE(tf);

    if (manual_feed > 0)
    {
	OUTSTR("end");
	NEWLINE(tf);
    }
    manual_feed--;

    OUTSTR("restore");
    NEWLINE(tf);

    for (k = 1; k <= copies; ++k)
	OUTCHAR('\f'); /* output FF's for print spooler page accounting */

    x = LEFT_X;
    y = TOP_Y(top_margin);
}

void
End_Line()
{
    if (scribe)
    {
	OUTCHAR(' ');
	OUTCHAR('E');
    }
    NEWLINE(tf);
}


void
End_Text(c)
char c;
{
    register int k;

    k = level;
    while (level > 0)
    {
	OUTCHAR(')');
	level--;
    }
    if (k > 0)
    {
	if (scribe)
	    OUTCHAR('W');
	else
	    OUTCHAR('P');
    }
    if (c)
    {
	OUTCHAR(' ');
	OUTCHAR(c);
    }
}

#include "inch.h"

int
inchar(fp)
FILE *fp;
{
    static int lastc = NUL;	/* memory of previous input character */
    register int c;

    /* output is incorrect if the file does not end with a LF; this
    routine supplies one at EOF if it is lacking */

    c = getc(fp);
    if ((c == EOF) && (lastc != '\n'))
	c = '\n';
    lastc = c;
    return (c);
}

void
Page_Switch(parg)			/* parg -> "Nxxxnnn" */
register char *parg;
{
    register char *porg;

    porg = parg;
    do_page_number = TRUE;
    init_page_number = 1;
    page_flag = (PAGE_T | PAGE_C);    /* default location */
    while (*++parg)
    {
	switch(*parg)
	{
	case 't':
	case 'T':
	    page_flag &= ~(PAGE_B | PAGE_T);
	    page_flag |= PAGE_T;
	    break;

	case 'b':
	case 'B':
	    page_flag &= ~(PAGE_B | PAGE_T);
	    page_flag |= PAGE_B;
	    break;

	case 'l':
	case 'L':
	    page_flag &= ~(PAGE_L | PAGE_C | PAGE_R);
	    page_flag |= PAGE_L;
	    break;

	case 'c':
	case 'C':
	    page_flag &= ~(PAGE_L | PAGE_C | PAGE_R);
	    page_flag |= PAGE_C;
	    break;

	case 'r':
	case 'R':
	    page_flag &= ~(PAGE_L | PAGE_C | PAGE_R);
	    page_flag |= PAGE_R;
	    break;

	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	    init_page_number = atoi(parg);
	    while (isdigit(*parg))
		++parg;
	    if (*parg == NUL)
		break;
			    /* else fall through to error exit */
	default:
	    NEWLINE(stderr);
	    (void)fprintf(stderr,
		"?Unrecognized page number field [%s]",porg);
	    NEWLINE(stderr);
	    EXIT(1);
	}
	if (*parg == NUL)
	    break;
    }
}

#include "strcm2.h"
