File:  [MW Coherent from dump] / coherent / d / bin / lpr / hp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * hp.c
 * 11/13/90
 * Hewlett Packard LaserJet printer filter.
 * Translate page format and nroff font information
 * into HP LaserJet printer escape sequences (PCL).
 * Usage: hp [-acflr] [-in] [-pn] [-tn] [file ...]
 * Options:
 *	-a	Use HP font acute accent character for '\''; default is '\''.
 *	-c	Font cartridge not available, use underline for italics.
 *	-f	[Archaic] Print pages in normal order; this is now the default.
 *	-in	Set left margin (indent) to n; default is 0.
 *	-l	Print in landscape mode; default is portrait mode.
 *	-pn	Set text length to n; default is NLINES, i.e. 66.
 *	-r	Print pages in reverse order (for LaserJet I).
 *		[Writes to temp FILE 'output', then readback() rewrites
 *		temp file to stdout with pages reversed.]
 *	-tn	Set top margin to n; default is 0.
 * Exit status is 0 if successful, 1 if error, 2 if interrupted.
 *
 * Edit history:
 *	3/21/85	(jtk) -- Changed so that pages were printed in reverse order,
 *		and fixed bug where trailing lines with only
 *		non-blank character were deleted.
 *	4/09/85 (ella) -- Changed so that pages were printed in
 *		the landscape mode with the pitch 16.66, and 
 *		fixed bug where underlining in the landscape mode
 *		and/or !cartridge wasn't ever terminated.
 *		Incorporated rma's fix (-a option) to reflect the
 *		manual page and properly process acute accents:
 *		default: straight (apostrophe), with -a: slanted
 *		(single quote).
 *		Included all available options into Usage message.
 *	10/31/90 (norm) -- fixed the brain damage regarding
 *		formfeeds. Change default to printing pages in
 *		order since almost all printers do.  Close any
 *		files that we open. Guess that shows how much testing
 *		was done by the author...
 *	11/7/90	(steve) -- Reordered and rewrote text extensively
 *		for legibility, hopefully no substantive changes.
 */

#include <stdio.h>
#include <signal.h>

extern	long	ftell();

/* Miscellany. */
#define	VERSION		"1.3"
#define	ACCENTACUTE	0xA8
#define	ACCENTGRAVE	0xA9
#define	LINESZ		512
#define	NLINES		66
#define	NPAGES		1000
#define	USAGEMSG	"Usage: hp [ -acflr ] [ -in ] [ -pn ] [ -tn ] [ file ... ]"

/* Fonts. */
#define	ROMAN_F		0		/* all except below means Roman */
#define	BOLD_F		1		/* "x\bx" means bold 'x' */
#define	ITALIC_F	2		/* "_\bx" means italic '_' */

/* HP Printer Control Language (PCL) commands. */
/* These are printf() format strings, some require additional arguments. */
#define	HMOVEFWD	"\033&a+%dH"
#define	HMOVEBACK	"\033&a-%dH"
#define	LANDSCAPE	"\033&l%dO"	/* arg 0==portrait, 1==landscape */
#define	LEFTMARGIN	"\033&a%dL"
#define	LINESPACING	"\033&l%dD"
#define	MOVETOCOL	"\033&a%dC"
#define	PAGELENGTH	"\033&l%dP"
#define	PITCH16		"\033(s16.66H"	/* pitch 16.66 cpi */
#define	RESET		"\033E"
#define	STROKEWEIGHT	"\033(s%dB"
#define	STYLE		"\033(s%dS"
#define	STYLEWEIGHT	"\033(s%ds%dB"
#define	TEXTLENGTH	"\033&l%dF"
#define	TOPMARGIN	"\033&l%dE"
#define	UNDEROFF	"\033&d@"
#define	UNDERON		"\033&dD"

/* Forward. */
#if	0
void	debug();
#endif
void	done();
void	fakebold();
void	fatal();
int	hasFF();
void	initialize();
void	newfont();
int	nonblank();
void	printfile();
void	printline();
void	readback();
void	trap();
void	usage();

/* Globals. */
int	aflag;			/* Accent flag				*/
char	*argv0;			/* Command name for error messages	*/
int	cartridge = 1;		/* Font cartridge is available		*/
int	font = ROMAN_F;		/* Current font				*/
int	landscape;		/* 0 for portrait mode, 1 for landscape	*/
int	leftmargin;		/* Left margin				*/
int	linespacing = 6;	/* Vertical lines per inch		*/
int	nfiles;			/* Number of files to print		*/
int	npages;			/* Number of pages marked on input	*/
FILE	*output = NULL;		/* FILE containing unreversed pages	*/
char	page[NLINES][LINESZ];	/* Current page buffer			*/
long	pageaddr[NPAGES];	/* Seek pointers to top of output pages	*/
int	quit;			/* Signal to interrupt program		*/
int	rflag;			/* Reverse page order			*/
char	tempfile[20];		/* Temporary file name			*/
int	textlength = NLINES;	/* Text length -- must satisfy		*/
				/*	textlength <= NLINES-topmargin	*/
int	topmargin;		/* Top margin				*/

main(argc, argv) int argc; char *argv[];
{
	/* Process arguments. */
	argv0 = argv[0];
	argc--;
	argv++;
	while (argc > 0)  {
		switch(**argv)  {
		case '-':
			switch(*++*argv)  {
			case 'a':
				aflag = 1;
				break;
			case 'c':
				cartridge = 0;
				break;
			case 'f':
				/* Recognized for historical reasons, ignore. */
				break;
			case 'i':
				leftmargin = atoi(++*argv);
				break;
			case 'l':
				landscape = 1;
				linespacing = 8;
				break;
			case 'p':
				textlength = atoi(++*argv);
				break;
			case 'r':
				rflag = 1;
				break;
			case 't':
				topmargin = atoi(++*argv);
				break;
			case 'V':
				fprintf(stderr, "%s: V%s\n", argv0, VERSION);
				break;
			default:
				usage();
				break;
			}
			break;
		default:
			if (nfiles++ == 0)
				initialize();
			printfile(*argv);
			break;
		}
		argv++;
		argc--;
	}

	/* If no command line files, process stdin. */
	if (nfiles == 0) {
		initialize();
		printfile(NULL);
	}

	/* Done. */
	if (rflag)
		readback();
	done(0);
}

#if	0
/*
 * Print debugging output to file "hp.db".
 */
/* VARARGS */
void
debug(s) char *s;
{
	register FILE *fp;

	if ((fp = fopen("hp.db", "ar")) == NULL)
		return;
	fprintf(fp, "hp: %r\n" &s);
	fclose(fp);
}
#endif

/*
 * Finish up.  Remove temporary file if it has been opened, then exit.
 */
void
done(status) int status;
{
	printf(RESET);
	if (output != NULL) {
		fclose(output);
		if (output != stdout)
			unlink(tempfile);
	}
	exit(status);
}

/*
 * Fake boldface of given character when font not available.
 */
void
fakebold(c) register int c;
{
	register int d;

	if (font != ROMAN_F)
		newfont(ROMAN_F);		/* terminate previous font */
	d = (landscape) ? 7 : 8;		/* decipoint distance */
	putc(c, output);			/* print it */
	fprintf(output, MOVETOCOL, -1);		/* move back one column */
	fprintf(output, HMOVEFWD, d);		/* and forward d decipoints */
	putc(c, output);			/* print it again */
	fprintf(output, HMOVEBACK, d);		/* and move back d decipoints */
}

/*
 * Print a fatal error message and die.
 */
/* VARARGS */
void
fatal(s) char *s;
{
	fprintf(stderr, "%s: %r\n", argv0, &s);
	done(1);
}

/*
 * Test whether string s contains a formfeed.
 */
int
hasFF(s) register char *s;
{
	register char c;

	while (c = *s++)
		if (c == '\f')
			return 1;
	return 0;
}

/*
 * Set interrupt trap and initialize the printer.
 * Open temporary file if rflag is specified,
 * otherwise output just goes to stdout.
 */
void
initialize()
{
	/* Trap SIGINT to set quit flag. */
	signal(SIGINT, trap);

	/* HP initialization. */
	printf(RESET);
	if (landscape)
		printf(PITCH16);
	printf(LANDSCAPE, landscape);
	printf(PAGELENGTH, NLINES);
	printf(LINESPACING, linespacing);
	printf(TOPMARGIN, topmargin);
	printf(TEXTLENGTH, textlength);
	printf(LEFTMARGIN, leftmargin);

	/* Initialize output file. */
	if (quit)
		done(2);
	if (rflag) {
		sprintf(tempfile, "/tmp/hptmp.%d", getpid());
		if ((output = fopen(tempfile, "wr")) == NULL)
			fatal("cannot open temporary file \"%s\"", tempfile);
	} else 
		output = stdout;
}

/* 
 * Change to a new font.
 * For each of the three fonts (ROMAN_F, BOLD_F, ITALIC_F),
 * this routine prints the font escape appropriate to the given configuration.
 * There are currently four possible printer configurations:
 *	normal	portrait  && cartridge
 *	-l	landscape && cartridge
 *	-c	portrait  && no cartridge
 *	-c -l	landscape && no cartridge
 * In the first case, do bold and italic with style and weight changes.
 * bold is faked from printline() per-character in the other cases,
 * italic is underlined Roman in the other cases.
 */
void
newfont(new) int new;
{
	static int style = 0;		/* initial style == upright */
	static int weight = 0;		/* initial weight == medium */
	static int under = 0;		/* initial underline state == off */
	register int newstyle, newweight, newunder;

	if (font == new)
		return;					/* unchanged */
	font = new;
	newstyle = newweight = newunder = 0;		/* defaults */
	switch(font) {
	case ROMAN_F:
		break;					/* upright medium */
	case BOLD_F:
		newweight = 1;				/* bold */
		break;
	case ITALIC_F:
		if (cartridge && !landscape) {
			newstyle = 1;			/* italic */
			newweight = -1;			/* weight -1 */
		} else
			newunder = 1;		/* underlined upright medium */
		break;
	default:
		fatal("unrecognized font type %d", font);
		break;
	}
	if (under != newunder) {
		under = newunder;
		fprintf(output, (under) ? UNDERON : UNDEROFF);
	}
	if (style != newstyle && weight != newweight) {
		style = newstyle;
		weight = newweight;
		fprintf(output, STYLEWEIGHT, style, weight);
	} else if (style != newstyle) {
		style = newstyle;
		fprintf(output, STYLE, style);
	} else if (weight != newweight) {
		weight = newweight;
		fprintf(output, STROKEWEIGHT, weight);
	}
}

/*
 * Return 1 if line s is not blank.
 */
int
nonblank(s) register char *s;
{
	register int c;

	while ((c = *s) == ' ' || c == '\t')
		s++;
	return (c != '\0' && c != '\n' && c != '\f');
}

/*
 * Print a file.
 * NULL means stdin.
 */
void
printfile(file) char *file;
{
	FILE *fp;
	register int i;
	int last, end;

	if (file == NULL)
		fp = stdin;
	else if ((fp = fopen(file, "r")) == NULL)
		fatal("cannot open file \"%s\"", file);

	if (font != ROMAN_F)
		newfont(ROMAN_F);
	for (end = 0; !end; ) {
		if (rflag) {
			if (npages >= NPAGES)
				fatal("more than %d pages", NPAGES);
			pageaddr[npages++] = ftell(output);
		}
		for (i = 0; i < NLINES; i++) {
			if (fgets(&page[i][0], LINESZ, fp) == NULL) {
				if (i == 0) {
					npages--;	/* last page empty */
					return;
				}
				end = 1;
				break;
			} else if (hasFF(page[i])) {	/* formfeed seen */
				++i;
				break;
			}
		}
		for (last = --i; last >= 0; --last)
			if (nonblank(page[last]))
				break;			/* nonblank line */
		for (i = 0; i <= last; i++)
			printline(page[i]);
		putc('\r', output);
		if (last < NLINES - 1)
			putc('\f', output);
	}
	if (file != NULL)
		fclose(fp);
}

/*
 * Print one line, substituting special characters from the HP character set.
 */
void
printline(cp) register char *cp;
{
	register int c1, c2, new;
	char *s;

	/* Replace accents with equivalents from the extended character set. */
	for (s = cp; *s != '\0'; ++s) {
		if (*s == '\'' && aflag)
			*s = ACCENTACUTE;
		else if (*s == '`')
			*s = ACCENTGRAVE;
	}

	/* Look for nroff font sequences. */
	while ((c1 = *cp++) != '\0') {

		/* Check for the interrupt signal. */
		if (quit)
			done(2);

		/* By default, Roman c1 gets printed at the end of this loop. */
		new = ROMAN_F;
		if (c1 == '\f')
			return;		/* chars after FF on line get eaten */
		else if (c1 == ' ' || c1 == '\t')
			new = font;	/* no font change on whitespace */
		else if (c1 == '_') {
			if ((c2 = *cp++) == '\b') {
				/* "_\bx" means italic x. */
				new = ITALIC_F;
				c1 = *cp++;
			} else
				cp--;		/* put back c2 */
		} else if ((c2 = *cp++) == '\b') {
			if ((c2 = *cp++) == c1) {
				/* "x\bx" means bold x. */
				if (!cartridge || landscape) {
					fakebold(c1);	/* fake it */
					continue;
				} else
					new = BOLD_F;
			} else
				cp -= 2;	/* put back '\b' and c2 */
		} else
			cp--;			/* put back c2 */
		if (font != new)
			newfont(new);		/* font change */
		putc(c1, output);		/* print c1 in new font */
	}
}

/*
 * Copy the temporary file to stdout with the pages in reverse order.
 */
void
readback()
{
	char c;

	while (--npages >= 0) {
		/* Check for interrupt signal at each page. */
		if (quit)
			done(2);
		fseek(output, pageaddr[npages], 0);
		while ((c = getc(output)) != '\f')
			putchar(c);
		putchar(c);
	}
}

/*
 * Set quit flag when interrupt signal is received.
 */
void
trap()
{
	quit = 1;
}

/*
 * Print a usage message and die.
 */
void
usage()
{
	fprintf(stderr, "%s\n", USAGEMSG);
	exit(1);
}

/* end of hp.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.