[net.sources] Program to convert text to postscript

stephenf@elecvax.eecs.unsw.oz (Stephen Frede) (11/05/85)

# Lpscript is a program which converts plain text into postscript. (For the
# Apple LaserWriter etc.) It is quite simple, and is useful for printing
# program listings and the like.
# Please send any bug reports/fixes or modifications to
#
#	...!seismo!munnari!elecvax.oz!stephenf	UUCP
#	stephenf@elecvax.oz			ACSNET
#
#
# -----------------------------------------------------------------------
# This is a shell archive.  Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file".  (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# lpscript.1 lpscript.c

echo x - lpscript.1
cat > "lpscript.1" << '//E*O*F lpscript.1//'
.TH LPSCRIPT 1
.SH NAME
lpscript \- convert text to postscript
.SH SYNOPSIS
.B lpscript
[-o[offset]] [-r[rotation]] [-s[fontsize]] [-f[font]] [-p[pitch]] [file ...]
.SH DESCRIPTION
.I Lpscript
reads text from standard input (or files if specified) and produces
postscript output, suitable for sending to any postscript device (such
as an Apple Laserwriter) or for using with any program that expects
postscript input (such as a postscript interpreter used to drive some
other raster device).
Text is normally aligned at the top and left with the imageable region
of the page (probably slightly smaller than the physical page size),
and a new page is taken whenever text would fall below this imageable
region.
The following options are understood, with all values able to be given
as integer or real:
.TP
.B \-o[distance]
Offset the text from the left edge of the imageable region, by the given
distance (in centimeters).
If \fB-o\fP is specified without a distance, 1 cm is assumed.
.TP
.B \-r[angle]
Rotate the page by the given angle, specified in degrees.
If no angle is specified, 90 degrees is assumed.
Normally, the page will be printed in portrait mode, ie with the
long axis vertical.
This option allows printing in landscape mode
(with the long axis horizontal).
Note that specifying an angle other than 0 or 90 will almost
certainly cause part of the text to fall outside the imageable region,
which serves you right for trying to be silly.
.TP
.B \-s[size]
Set the font size to the value given (in points) (72 points = 1 inch).
If a size is omitted, 12 is assumed.
The default point size without using this option is 10.
Specifying point sizes greater than 200 is probably silly and
certainly wastes toner.
.TP
.B \-p[pitch]
Set the line spacing of printed text to this value.
Giving a value here will cause the line spacing to be set to that
value, in points (72 points = 1 inch).
The default action is to set the line spacing to be 2 points more than
the font size.
.TP
.B \-f[fontname]
Set the font used to the name given.
The default font is `Courier'.
If this argument is given without a fontname, `Times-Roman' is used.
The list of available fonts (for the Apple Laser-Writer) is: `Times-Roman'
; `Times-Italic'
; `Times-Bold'; `Times-BoldItalic'; `Courier'; `Courier-Oblique'
; `Courier-Bold'; `Courier-BoldOblique'; `Helvetica'; `Helvetica-Bold'
; `Helvetica-Oblique'; `Helvetica-BoldOblique'.
Note that only the Courier family is a fixed-width font; all the others
are variable width, and so program listings or columns of data will
not line up.
.TP
.B \-h[space]
Increase the horizontal spacing of characters by the given fraction of
the current font size.
For example, using `-h0.25' with a font size of 12 points in effect,
would cause an increase of horizontal spacing by 3 points.
By default, the characters are placed next to each other, using the
natural width of the characters.
.SH AUTHOR
Stephen Frede, UNSW, Australia
//E*O*F lpscript.1//

echo x - lpscript.c
cat > "lpscript.c" << '//E*O*F lpscript.c//'
/*
 *	lpscript
 *
 *	Convert plain text to postscript
 *	- Stephen Frede, UNSW, Australia
 */

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

#define	INCH		72.0		/* no. postscript units / inch */
#define	CM		28.35		/* postscript units / cm */
#define	PAGEOFFSET	(1.0*CM)
#define	FONTSIZE	10.0		/* default font size (in points) */
#define	TABSIZE		8
#define	ROTATION	0.0		/* default orientation */
#define	FONT		"Courier"
#define NEW_PAGE	014		/* ^L forces a new page */

#define	TRUE		1
#define	FALSE		0

typedef char	int;

FILE		*ostr;

char	usage[] = "Valid lpscript options:\n\t-o[offset]\n\t-r[rotation]\n\t-s[fontsize]\n\t-p[pitch]\n\t-f[font]\n";
int	tabsize;		/* in character positions */

main(argc, argv)
int	argc;
char	**argv;
{
	int	status = 0;	/* exit status (no. errors occured) */
	float	pageoffset,
		fontsize,
		linepitch,
		spacing,
		rotation;
	char	*fontname;
	FILE	*istr;

	fontsize = FONTSIZE;
	pageoffset = 0.0;
	spacing = 0.0;
	tabsize = TABSIZE;
	rotation = ROTATION;
	fontname = FONT;
	ostr = stdout;
	argv++;		/* skip program name */
	while(*argv && **argv == '-')
	{
		char	c;

		(*argv)++;	/* skip the '-' */
		c = **argv;	/* option letter */
		(*argv)++;	/* skip option letter */
		switch(c)
		{
			case 'o':	/* offset */
				if(**argv == '\0')
					pageoffset = PAGEOFFSET;
				else
					pageoffset = atof(*argv) * CM;
				break;

			case 'r':	/* rotation */
				if(**argv == '\0')
					rotation = 90.0;
				else
					rotation = atof(*argv);
				break;

			case 'p':	/* pitch (line spacing) */
				linepitch = atof(*argv);
				break;

			case 's':	/* font size */
				if(**argv == '\0')
					fontsize = 12.0;
				else
					fontsize = atof(*argv);
				break;

			case 't':	/* tab size */
				if(**argv == '\0')
					tabsize = 4;
				else
					tabsize = (int) atof(*argv);
				break;

			case 'f':	/* font */
				if(**argv == '\0')
					fontname = "Times-Roman";
				else
					fontname = *argv;
				break;

			case 'h':	/* horizontal spacing */
				if(**argv == '\0')
					spacing = 0.25;
				else
					spacing = atof(*argv);
				break;

			default:
				fprintf(stderr, "Unknown option: '%c'\n",
					**argv);
				status++;
				break;
		}
		argv++;
	}
	if(status)
	{
		fprintf(stderr, usage);
		exit(status);
		/* NOTREACHED */
	}
	if(linepitch == 0)
		linepitch = fontsize + 2;
	spacing *= fontsize;
	init(fontsize, pageoffset, linepitch, rotation, fontname, spacing);
	if(! *argv)
		process(stdin);
	else while(*argv)
	{
		if((istr = fopen(*argv, "r")) == NULL)
		{
			perror(*argv);
			status++;
		}
		else
		{
			process(istr);
			fclose(istr);
		}
		argv++;
	}
	putc('\004', ostr);
	exit(status);
}

process(istr)
FILE	*istr;
{
	register char	ch;
	register int	x;	/* used for tab calculations */

	x = 0;
	putc('(', ostr);
	while((ch=getc(istr)) != EOF)
	{
		if(ch < ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != NEW_PAGE)
		{
			ch = '?';
		}
		if(ch == '\t')
		{
			int	n = x + tabsize - (x % tabsize);

			while(x++ < n)
				pch(' ');
		}
		else if(ch == '\n')
		{
			x = 0;
			fprintf(ostr, ") n\n");
			putc('(', ostr);
		}
		else if(ch == '\r')
		{
			x = 0;
			fprintf(ostr, ") r\n");
			putc('(', ostr);
		}
		else if(ch == NEW_PAGE)
		{
			x = 0;
			fprintf(ostr, ") n p\n");
			putc('(', ostr);
		}
		else
		{
			pch(ch);
			x++;
		}
	}
	fprintf(ostr, ") n p\n\f");
}

char	*inittab[] = {
	/* print a page and start a new one */
	"/p { copypage erasepage newpath 0 pgtop moveto } def",
	"/n",
	/* show the string given as an arg */
	"{ spacing 0 3 -1 roll ashow",
	/* now move down a line; linepitch is -'ve */
	"  0 linepitch rmoveto",
	/* save the new y posn */
	"  /y currentpoint exch pop def",
	/* test if the next line would be below the bottom margin */
	"  y 0 lt",
	/* if so, print the page, and move to the top of a new page */
	"  { p }",
	/* else go to where the next line is due to start */
	"  { 0 y moveto } ifelse",
	"} def",
	"/r",
	/* show the string given as an arg */
	"{ spacing 0 3 -1 roll ashow",
	/* save y */
	"  /y currentpoint exch pop def",
	/* and then move to the beginning of the current line */
	"  0 y moveto",
	"} def",
	(char *)0 };

init(fontsize, pageoffset, linepitch, rotation, fontname, spacing)
float	fontsize,
	pageoffset,
	linepitch,
	spacing,
	rotation;
char	*fontname;
{
	register char	**p;

	fprintf(ostr, "\004\n");
	p = inittab;
	while(*p)
		fprintf(ostr, "%s\n", *p++);
	fprintf(ostr, "/%s findfont %.1f scalefont setfont\n",
		fontname, fontsize);
	fprintf(ostr, "/linepitch %.1f def\n", -linepitch);
	fprintf(ostr, "/spacing %.1f def\n", spacing);
	/* apply rotation transformation, if any */
	if(rotation != 0.0)
		fprintf(ostr, "%.1f rotate\n", rotation);
	/* get current imageable area */
	fprintf(ostr, "clippath pathbbox\n");
	/* save the upper right y coordinate */
	fprintf(ostr, "/pgtop exch def\n");
	/* save lower left y; translate origin to lower left */
	fprintf(ostr, "pop /y exch def y translate\n");
	/* subtract old lower left from upper right to get top of page */
	/* then subtract linespacing (add -'ve) to get top text row */
	fprintf(ostr, "/pgtop pgtop y sub linepitch add def\n");
	/* apply horizontal offset, if any */
	/* unfortunately, a slight fudge factor is required here */
	fprintf(ostr, "%.1f 0 translate\n", pageoffset + 4);
	/* move to top of page, ready to start printing */
	fprintf(ostr, "newpath 0 pgtop moveto\n");
}

pch(ch)
int	ch;
{
	if(ch < ' ' || ch > '~')
		fprintf(ostr, "\\%3.3o", ch);
	else
	{
		if(ch == '(' || ch == ')' || ch == '\\')
			putc('\\', ostr);
		putc(ch, ostr);
	}
}
//E*O*F lpscript.c//

exit 0