*BSD News Article 25375


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!sgiblab!pacbell.com!toad.com!curt
From: curt@mofo.toad.com (Curt mayer)
Newsgroups: comp.os.386bsd.apps
Subject: PCL filter, file printer for HP and clones
Message-ID: <42821@toad.com>
Date: 27 Dec 93 19:52:58 GMT
Sender: news@toad.com
Followup-To: comp.os.386bsd.questions
Distribution: world
Organization: Mofo
Lines: 591
Summary: the postscript tyranny is over
Nntp-Posting-Host: mofo.toad.com

-----------------------cut here---------------------
: To unbundle, sh this file
mkdir .
echo ./README
cat >./README <<'@@@ Fin de ./README'

This package makes HP PCL printers work under Freebsd. it should also
work under netbsd, and others to come.

to install:

copy the printcap file to /etc

copy the hpf subdirectory to /usr/src/usr.sbin/lpr/filters

change the line in /usr/src/usr.sbin/lpr/filters/Makefile to read:

	SUBDIR= hpf lpf lzcat

cd to /usr/src/usr.sbin/lpr/filters
make ; make install

then, copy the print subdirectory wherever; I have it in /usr/src/usr.bin
cd there;
make ; make install

make sure you have the appropriate parallel driver configured. I use lpa0.

enjoy.
@@@ Fin de ./README
mkdir ./hpf
echo ./hpf/Makefile
cat >./hpf/Makefile <<'@@@ Fin de ./hpf/Makefile'
#	@(#)Makefile	5.9 (Berkeley) 5/13/90

PROG=	hpf
NOMAN=	noman
BINDIR=	/usr/libexec/lpr

.include <bsd.prog.mk>
@@@ Fin de ./hpf/Makefile
echo ./hpf/README
cat >./hpf/README <<'@@@ Fin de ./hpf/README'
this directory needs to go into /usr/src/usr.sbin/lpr/filters
it makes an hp printer do the right thing.
you also need to tweak the makefile in /usr/src/usr.sbin/lpr appropriately
@@@ Fin de ./hpf/README
echo ./hpf/hpf.c
cat >./hpf/hpf.c <<'@@@ Fin de ./hpf/hpf.c'
#include "stdio.h"
#include <signal.h>
#include <sys/file.h>
#include <sys/ioctl.h>

int nomap = 0;

main(ac, av)
int ac;
char **av;
{

	while(ac > 1 && av[1][0] == '-') {
		switch(av[1][1]) {
			case 'c':
				nomap = 1;
				break;
			default:
				break;
		}
		ac--;
		av++;
	}

	lzinit();
	hpcat();
	hpdone();
	exit(0);
}

#include <sgtty.h> 

lzinit()
{
	struct sgttyb nbuf;
	unsigned long lbits;

	setbuf(stdout, NULL);
	lbits = LDECCTQ | LPASS8 | LLITOUT;
	ioctl(fileno(stdout), TIOCLSET, &lbits);
	ioctl(fileno(stdout), TIOCGETP, &nbuf);
	nbuf.sg_flags &= ~(ECHO | XTABS | CRMOD);
	ioctl(fileno(stdout), TIOCSETP, &nbuf);
	fputs("\033E\033&k2G", stdout);
}

hpcat()
{
	int c, c2, cnt = 0;

	while((c = getchar()) != EOF) {
		switch (c) {
		case '\t':
			do {
				putchar(' ');
				cnt++;
			} while(cnt%8 != 0);
			break;

		case '\031':
			c2 = getchar();
			if (c2 == '\001') {
				kill(getpid(), SIGSTOP);
				break;
			} else {
				ungetc(c2, stdin);
			}
			/* fall through */
		default:
			putchar(c);
			if(c == '\f' || c == '\n') {
				cnt = 0;
			} else cnt++;
		}
	}
}

hpdone()
{
	fputs("\033&l0H", stdout);
}

@@@ Fin de ./hpf/hpf.c
mkdir ./print
echo ./print/Makefile
cat >./print/Makefile <<'@@@ Fin de ./print/Makefile'
#	@(#)Makefile	5.3 (Berkeley) 5/11/90

PROG=	print

.include <bsd.prog.mk>
@@@ Fin de ./print/Makefile
echo ./print/README
cat >./print/README <<'@@@ Fin de ./print/README'
this directory contains a PCL5 print formatter that prints 2 up.
it also should work on PCL4.
it has been tested on FreeBSD 1.0. 
it should work elsewhere.
it is free software. 
all rites reversed.
just don't claim you wrote it.
@@@ Fin de ./print/README
echo ./print/print.1
cat >./print/print.1 <<'@@@ Fin de ./print/print.1'
.\"
.Dd November 18, 1993
.Dt PRINT 1
.Os
.Sh NAME
.Nm print
.Nd queue text files to PCL4 printer.
.Sh SYNOPSIS
.Nm print
.Op Fl s
.Op Fl l
.Op Fl t Ar tabwidth
.Op Fl p Ar printer_name
.Op Ar text_file ...
.Sh DESCRIPTION
.Nm Print
prints files 2 pages side by side on 1 piece of paper on PCL4 printer.
If no files are specified, it reads stdin. 
.Nm Print
usually does the right thing with nroff output. It fakes boldface rather well.
.Pp
Options:
.Bl -tag -width Ds
.It Fl s
Specify graphically simple output, without the gaudy borders.
.It Fl l
Specify formatting for 60 lines per page, instead of the default 66.
.It Fl t
Specify the tab width. The default of 4 may irritate purists.
.It Fl p
Specify the printer to spool to. The default printer is named
.Em lj.
.Sh ENVIRONMENT
If the following environment variables exist, they are used by
.Nm print:
.Bl -tag -width PAGELENGTH
.It Ev PRINTER
Specifies an alternate printer.
.It Ev TABWIDTH
Specifies the tab stop width.
.It Ev PAGELENGTH
Specifies the page length. it may take the value of 60 or 66.
.Sh AUTHOR
curt@toad.com
.Sh BUGS
There is no way to communicate a jobname to lpr. 
This is really a bug with BSD, since it has no printer access library.
Hasn't been tested on a real HP laserjet.
@@@ Fin de ./print/print.1
echo ./print/print.c
cat >./print/print.c <<'@@@ Fin de ./print/print.c'
/*
 * take a list of filenames, and print the files 2 up on a PCL4 printer
 * Author:
 *	Curt Mayer: curt@toad.com
 * TODO:
 *	parameterize all fonts, so can do easily do 4 up someday.
 *
 * this source has tabs set at 4.
 */
#include	<stdio.h>
#include	<sys/types.h>
#include	<sys/stat.h>

/*
 * mess with these numbers at your own peril - they are the result of
 * much jiggery-pokery
 */

/* size of printable region in dots */
#define	DOTSHIGH	2320
#define	DOTSWIDE	3120

/* these are in units of vmi and hmi of the page font */
#define	TOPOFF		4
#define	LEFTMARGIN	6
#define	STARTSIDE1	87
#define	CONTOFF		2

/* height of shaded region in dots */
#define	TOPLINE		80

/* offset of printable region in dots */
#define	TOPDOTS		50
#define	LEFTDOTS	50

/* width of rule lines on page in dots */
#define	LINEWIDTH	2

/* header font */
#define	HFONTPOINTS	12
#define	HFONTPITCH	10

/* the header font size in dots */
#define	HFONTHEIGHT	((HFONTPOINTS * 100) / 24)
#define	HFONTWIDTH	(300 / HFONTPITCH)

/* offset from left and right of header strings in dots */
#define	TEXTMARGIN	50

/* these are for the page font */
#define	VMI_66		"5.5"
#define	VMI_60		"6.1"
#define	HMI			"7.2"
#define	BOLDOFF		"0.6"

#define	CONTCHAR	'+'
#define	LPRCMD		"lpr -P%s -h >/dev/null 2>&1"

#define	LP_DEFAULT		"lj"
#define	TAB_DEFAULT		4
#define	PAGELEN_DEFAULT	66

char cmdbuf[80];

char *printer = LP_DEFAULT;
int tabstop = TAB_DEFAULT;
int pagelen = PAGELEN_DEFAULT;

char *vmi;
int gaudy = 1;
int line;
int side;
int col;
int pagenum;

FILE *pp;
char *filename;
time_t now;

extern FILE *popen(), *fopen();
extern char *ctime();
extern char *getenv();

extern char *optarg;
extern int optind;
extern int opterr;
extern int getopt();

main(argc, argv)
int argc;
char *argv[];
{
	FILE *fp;
	struct stat statb;
	int i, c;
	char *e;

	time(&now);

	if (e = getenv("PRINTER")) {
		printer = e;
	}

	if (e = getenv("TABWIDTH")) {
		tabstop = atoi(e);
	}

	if (e = getenv("PAGELEN")) {
		pagelen = atoi(e);
	}

	opterr = 0;
	while ((c = getopt(argc, argv, "slt:p:")) != EOF) {
		switch(c) {
		case 'l':
			pagelen = 60;
			break;
		case 's':
			gaudy = 0;
			break;
		case 't':
			tabstop = atoi(optarg);
			break;
		case 'p':
			printer = optarg;
			break;
		case '?':
		default:
			fprintf(stderr, 
				"%s: [-sl] [-t <tabstop>] [-p <printer>] [<file> ...]\n", 
				argv[0]);
			exit(-1);
		}
	}

	if (tabstop == 0) {
		tabstop = TAB_DEFAULT;
	}

	switch (pagelen) {

	case 66:
#if PAGELEN_DEFAULT == 66
	default:
#endif
		vmi = VMI_66;
		pagelen = 66;
		break;

	case 60:
#if PAGELEN_DEFAULT == 60
	default:
#endif
		vmi = VMI_60;
		pagelen = 60;
		break;
	}

	argc -= optind;
	argv += optind;

	if (argc == 0) {
		filename = "stdin";
		sendjob(stdin);
	} else {
		for (i = 0; i < argc; i++) {
			filename = argv[i];

			if (stat(filename, &statb) != 0) {
				perror(filename);
				continue;
			}

			if ((statb.st_mode & S_IFMT) != S_IFREG) {
				fprintf(stderr, "print: %s not a regular file\n", filename);
				continue;
			}

			fp = fopen(filename, "r");
			if (fp == NULL) {
				fprintf(stderr, "print: can't open %s\n", filename);
				continue;
			}
			
			sendjob(fp);
			fclose(fp);
		}
	}
	if (pp)
		pclose(pp);
	exit (0);
}

sendjob(fp)
FILE *fp;
{
	int c;
	int lastc;

	if (!pp) {
		sprintf(cmdbuf, LPRCMD, printer);
		pp = popen(cmdbuf, "w");
		if (pp == NULL) {
			fprintf(stderr, "print: can't pipe to line printer\n");
			exit(1);
		}
	}

	line = 0;
	side = 0;
	col = 0;
	pagenum = 1;

	fprintf(pp, "\033E");
	fprintf(pp, "\033&k2G");
	fprintf(pp, "\033&l1O");
	fprintf(pp, "\033(s0P");
	fprintf(pp, "\033&l0L");
	fprintf(pp, "\0339");
	fprintf(pp, "\033&l0E");

	drawpage();
	fprintf(pp, "\033&a%dr%dC", TOPOFF + line, LEFTMARGIN + side * STARTSIDE1);

	while ((c = getc(fp)) != EOF) {
		switch (c) {
		case 0x0c:
			c = getc(fp);
			if (c != EOF) {
				line = pagelen - 1;
				do_newline(0);
			}
			ungetc(c, fp);
			break;
		case '\n':
			do_newline(0);
			break;
		case '\t':
			do {
				putc(' ', pp);
			} while (++col % tabstop);
			break;
		case 0x8:
			if (col) {
				col--;
				fprintf(pp, "\033&a%dr%dC", 
					TOPOFF + line, LEFTMARGIN + side * STARTSIDE1 + col);
				c = getc(fp);
				if (c == lastc) {
					fprintf(pp, "\033&k%sH \033&k%sH%c", BOLDOFF, HMI, c);
					col++;
					fprintf(pp, "\033&a%dr%dC", 
						TOPOFF + line, LEFTMARGIN + side * STARTSIDE1 + col);
				} else {
					ungetc(c, fp);
				}
			}
			break;
		default:
			if (col >= 80) {
				do_newline(1);
			}
			if (c < ' ')
				c = 0x7f;
			putc(c, pp);
			col++;
			lastc = c;
			break;
		}
	}
	fprintf(pp, "\033E");
}

do_newline(wrap)
int wrap;
{
	putc('\n', pp);
	if (++line == pagelen) {
		if (side == 1) {
			side = 0;
			pagenum++;
			fprintf(pp, "\014");
			drawpage();
		} else {
			side = 1;
		}
		line = 0;
	}
	if (wrap) {
		fprintf(pp, "\033&a%dr%dC%c", TOPOFF + line,
			LEFTMARGIN + side * STARTSIDE1 - CONTOFF, CONTCHAR);
	}
	fprintf(pp, "\033&a%dr%dC", TOPOFF + line,
		LEFTMARGIN + side * STARTSIDE1);
	col = 0;
}

drawpage()
{
	char page[5];

	sprintf(page, "%d", pagenum);

	/* draw vertical line */
	fprintf(pp, "\033*p%dx%dY", (DOTSWIDE / 2) + LEFTDOTS, TOPLINE + TOPDOTS);
	fprintf(pp, "\033*c%da%dB", LINEWIDTH, DOTSHIGH);
	fprintf(pp, "\033*c0P");

	if (gaudy) {
		/* draw filled horizontal rectangle */
		fprintf(pp, "\033*p%dx%dY", LEFTDOTS, TOPDOTS);
		fprintf(pp, "\033*c%da%dB", DOTSWIDE, TOPLINE);
		fprintf(pp, "\033*c8G");
		fprintf(pp, "\033*c2P");

		/* top line */
		fprintf(pp, "\033*p%dx%dY", LEFTDOTS, TOPDOTS);
		fprintf(pp, "\033*c%da%dB", DOTSWIDE, LINEWIDTH);
		fprintf(pp, "\033*c0P");

		/* middle line */
		fprintf(pp, "\033*p%dx%dY", LEFTDOTS, TOPLINE + TOPDOTS);
		fprintf(pp, "\033*c%da%dB", DOTSWIDE, LINEWIDTH);
		fprintf(pp, "\033*c0P");

		/* left line */
		fprintf(pp, "\033*p%dx%dY", LEFTDOTS, TOPDOTS);
		fprintf(pp, "\033*c%da%dB", LINEWIDTH, DOTSHIGH + TOPLINE);
		fprintf(pp, "\033*c0P");

		/* right line */
		fprintf(pp, "\033*p%dx%dY", DOTSWIDE + LEFTDOTS, TOPDOTS);
		fprintf(pp, "\033*c%da%dB", LINEWIDTH, DOTSHIGH + TOPLINE);
		fprintf(pp, "\033*c0P");

		/* bottom line */
		fprintf(pp, "\033*p%dx%dY", LEFTDOTS, DOTSHIGH + TOPLINE + TOPDOTS);
		fprintf(pp, "\033*c%da%dB", DOTSWIDE, LINEWIDTH);
		fprintf(pp, "\033*c0P");
	} else {
		/* draw horizontal line */
		fprintf(pp, "\033*p%dx%dY", LEFTDOTS, TOPLINE + TOPDOTS);
		fprintf(pp, "\033*c%db%dB", DOTSWIDE, LINEWIDTH);
		fprintf(pp, "\033*c0P");
	}

	/* set header font */
	fprintf(pp, "\033(s3T");
	fprintf(pp, "\033(s3S");
	fprintf(pp, "\033(s%dV", HFONTPOINTS);
	fprintf(pp, "\033(s%dH", HFONTPITCH);

	/* print header line */
	fprintf(pp, "\033*p%dX", LEFTDOTS + TEXTMARGIN);
	fprintf(pp, "\033*p%dY", TOPDOTS + TOPLINE - (HFONTHEIGHT / 2));
	fputs(ctime(&now), pp);

	fprintf(pp, "\033*p%dX", 
		LEFTDOTS + (DOTSWIDE / 2) - ((strlen(page) * HFONTWIDTH) / 2));
	fprintf(pp, "\033*p%dY", TOPDOTS + TOPLINE - (HFONTHEIGHT / 2));
	fputs(page, pp);

	fprintf(pp, "\033*p%dX", 
		LEFTDOTS + DOTSWIDE - (strlen(filename) * HFONTWIDTH) - TEXTMARGIN);
	fprintf(pp, "\033*p%dY", TOPDOTS + TOPLINE - (HFONTHEIGHT / 2));
	fputs(filename, pp);

	/* set page font */
	fprintf(pp, "\033(s0T");
	fprintf(pp, "\033(s8.5V");
	fprintf(pp, "\033(s16.6H");
	fprintf(pp, "\033&l%df%sC", pagelen, vmi);
}
@@@ Fin de ./print/print.c
echo ./printcap
cat >./printcap <<'@@@ Fin de ./printcap'
#	@(#)printcap	5.3 (Berkeley) 6/30/90

lp|lj|local line printer:\
	:lp=/dev/lpa0:sd=/var/spool/lpd:lf=/var/log/lpd-errs:\
	:of=/usr/libexec/lpr/hpf:if=/usr/libexec/lpr/hpf:sh:mx#0:pw#80:
@@@ Fin de ./printcap
exit 0
-- 
	curt mayer
        curt@toad.com
        415-387-0217 home