/*
 *	lpscript
 *
 *	Convert plain text to postscript
 *	- Stephen Frede, UNSW, Australia
 *
 *	Ported to UT Instructional VAXcluster 05-Feb-1986 by Mic Kaczmarczik
 *	This version also has conditional code for the Utah PCC-20 compiler
 *
 *	Modifications:
 *
 *	05-Feb-1986	MPK
 *		+ -c (copies) switch
 *		+ -o (output) switch
 *		+ -m (top margin) switch
 *		+ change -o (offset) to -i (indent)
 *		+ #ifdef VAXC for string.h because VAX C doesn't have it
 *
 *	14-Apr-86	MPK
 *		+ fix bug in process() in case '\t' -- x was being
 *		  incremented automatically inside while loop
 *		  instead of when we really put a space out. This
 *		  was screwing up tab stops.
 *		+ add code to process() to handle backspace characters.
 *		  this feature doesn't always produce wonderful output
 *		  with proportional fonts, but it handles typical line-printer
 *		  underlining and overstriking.
 *		+ avoid putting lines more than 80 chars long in output file.
 *		  The line on the Postscript page is unaffected by this, but
 *		  it keeps print symbionts and other record-oriented things
 *		  happy.
 *		+ add -b switch (bottom margin).
 *
 *	Bugs:
 *		+ The margin settings need to be more uniform.
 */

#include	<stdio.h>
#ifdef VAXC
char	*strcat();
char	*strncat();
int	strcmp();
int	strncmp();
char	*strcpy();
char	*strncpy();
int	strlen();
char	*index();
char	*rindex();
#else
#include	<string.h>
#endif

#define	INCH		72.0		/* no. postscript units / inch */
#define	CM		28.35		/* postscript units / cm */
#define	PAGEOFFSET	(1.0*CM)
#define TOPMARGIN	(1.0*CM)	/* top margin of page */
#define BOTTOMMARGIN	(1.0*CM)	/* bottom margin of page */
#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:",
			"\t-b[bottommargin]",
			"\t-c[copies]",
			"\t-f[font]",
			"\t-h[spacing]",
			"\t-i[indent]",
			"\t-m[topmargin]",
			"\t-o[file]",
			"\t-p[pitch]",
			"\t-r[rotation]",
			"\t-s[fontsize]",
			"\t-t[tabsize]",
			(char *) 0
		};

int	tabsize;		/* in character positions */

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

	fontsize = FONTSIZE;
	pageoffset = 0.0;
	topmargin = 0.0;
	bottommargin = 0.0;
	spacing = 0.0;
	tabsize = TABSIZE;
	rotation = ROTATION;
	fontname = FONT;
	copies = 1.0;

	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 'b':	/* bottom margin (MPK 12-Apr-86) */
				if(**argv == '\0')
					bottommargin = BOTTOMMARGIN;
				else
					bottommargin = atof(*argv) * CM;
				break;

			case 'c':	/* copies (MPK 05-Feb-86) */
				if(**argv == '\0')
					copies = 2.0;
				else
					copies = 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;

			case 'i':	/* indent */
				if(**argv == '\0')
					pageoffset = PAGEOFFSET;
				else
					pageoffset = atof(*argv) * CM;
				break;
			case 'm':	/* top margin (MPK) */
				if(**argv == '\0')
					topmargin = TOPMARGIN;
				else
					topmargin = atof(*argv) *CM;
				break;
			case 'o':	/* output file (MPK 05-Feb-86) */
				if (**argv != '\0') /* -o -> stdout */
				    if ((ostr = fopen(*argv,"w")) == NULL) {
					fprintf(stderr,"can't open output\n");
					exit(1);
				    }
				break;
			case 'p':	/* pitch (line spacing) */
				linepitch = atof(*argv);
				break;

			case 'r':	/* rotation */
				if(**argv == '\0')
					rotation = 90.0;
				else
					rotation = 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;

			default:
				fprintf(stderr, "Unknown option: '%c'\n",
					**argv);
				status++;
				break;
		}
		argv++;
	}
	if(status)
	{
		int i;
		for (i = 0; usage[i]; i++)
			fprintf(stderr, "%s\n", usage);
		exit(status);
		/* NOTREACHED */
	}
	if(linepitch == 0)
		linepitch = fontsize + 2;
	spacing *= fontsize;
	init(fontsize, pageoffset, topmargin, bottommargin, linepitch,
		rotation, copies, fontname, spacing);
	if(! *argv)
		process(stdin);
	else while(*argv
#ifdef TOPS20
 && (**argv != '\0')
#endif
		         ){
#ifdef TOPS20
		if (**argv == '>') {
			argv++;
			continue;
		}
#endif
		if((istr = fopen(*argv, "r")) == NULL)
		{
			perror(*argv);
			status++;
		}
		else
		{
			process(istr);
			fclose(istr);
		}
		argv++;
	}
	putc('\004', ostr);
#ifndef VAXC
	exit(status);
#endif
}

process(istr)
FILE	*istr;
{
	register char	ch;
	register int	x;	/* used for tab calculations */
	register int	ll;	/* keep track of output line length */

	x = ll = 0;
	putc('(', ostr);
	while((ch=getc(istr)) != EOF)
	{
		if(ch == '\b' && (x > 0))	/* MPK 14-Apr-86 */
		{
			x--;
			ll += 4;
			fprintf(ostr, ")b (");
		}
		else if(ch == '\t')
		{
			int	n = x + tabsize - (x % tabsize);

			while(x < n) {
				pch(' ');
				x++;
				ll++;
			}
		}
		else if(ch == '\n')
		{
			x = ll = 0;
			fprintf(ostr, ") n\n");
			putc('(', ostr);
		}
		else if(ch == '\r')
		{
			x = ll = 0;
			fprintf(ostr, ") r\n");
			putc('(', ostr);
		}
		else if(ch == NEW_PAGE)
		{
			x = ll = 0;
			fprintf(ostr, ") n p\n");
			putc('(', ostr);
		}
		/* default case. Avoid NULs and output line length problems */
		else if (ch != '\0')
		{
			pch(ch);
			x++;
			if (++ll > 80) { /* output line getting long - split */
				fprintf(ostr,") showstring\n");
				putc('(', ostr);
				ll = 0;
			}
		}
	}
	fprintf(ostr, ") n p\n\f");
}

char	*inittab[] = {
	/* show a string with appropriate spacing */
	"/showstring { spacing 0 3 -1 roll ashow } def",
	/* print a page and start a new one */
	"/p",
	/* print out as many copies as desired */
	"{ 1 1 copies { copypage pop } for\n",
	/* Erase the page and start over, saving graphics state */
	"  erasepage newpath 0 pgtop moveto } def",
	"/n",
	/* show the string given as an arg */
	"{ showstring",
	/* 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 bottommargin 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 */
	"{ showstring",
	/* save y */
	"  /y currentpoint exch pop def",
	/* and then move to the beginning of the current line */
	"  0 y moveto",
	"} def",
	/* implement a backspace operation -- show the string so far, */
	/* then back up to beginning of last character */
	"/b",
	" { dup () eq",
	/* fake a space if there's nothing there. */
	"    { pop ( ) stringwidth pop neg 0 rmoveto }",
	/* otherwise, extract last character in string and save it */
	"    { dup dup length 1 sub 1 getinterval exch",
	/* draw the string */
	"      showstring",
	/* move back by width of last character */
	"      stringwidth pop neg 0 rmoveto",
	"    } ifelse",
	" } def",
	(char *)0 };

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

	fprintf(ostr, "\004\n");
	p = inittab;
	while(*p)
		fprintf(ostr, "%s\n", *p++);
	fprintf(ostr, "/copies %d def\n",(int) copies);	/* MPK 05-Feb-86 */
	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);

	/* apply top margin, if any */
	fprintf(ostr, "/pgtop pgtop %.1f sub def\n", topmargin);

	/* set up bottom margin, if any */
	fprintf(ostr, "/bottommargin %.1f def\n",bottommargin);

	/* 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, "\\%03.3o", ch);
	else
	{
		if(ch == '(' || ch == ')' || ch == '\\')
			putc('\\', ostr);
		putc(ch, ostr);
	}
}

