Duplex (double sided) printing to an HP 8000
Glenn Burkhardt
glenn at aoi.ultranet.com
Fri Sep 17 15:45:45 EDT 1999
I use this filter for the HP4000, equipped with a duplex unit. It senses the
file type (text, Postscript, PCL), and sends the commands appropriate the
modes. I compile two editions, one for normal use, and one with -DDUPLEX
to turn on the duplexer, and then use a flag to use the filter that turns the
duplexer on. The printcap entry on our Sparc 5 is:
lz0|lps0|corridor_hp: \
:lp=/dev/bpp0:sh:ff=/f:sd=/var/spool/lz0:ms=-opost,crtscts:pl#60:mx#0\
:lf=/var/spool/lz0/errs:\
:if=/usr/local/bin/hplaser:df=/usr/local/bin/hplaser2sides:
so
lpr -Plz0 -d <filename>
will be printed with the duplexer on.
There's also a compile time mode that will invoke another filter 'hpps' that
uses Ghostscript to generate PCL code for non-Postscript printers. It has only
one line in it:
/usr/local/bin/gs -q -dNOPAUSE -sDEVICE=laserjet -sOutputFile=- -
Referencing it as a separate command allows changes, e.g., device driver,
without re-compilation.
-------------- next part --------------
/* @(#)hplaser.c 1.9 4/14/99
Taste the file to determine file type: PCL, text, Postscript. For
text files, expand tabs and put a CR before each LF.
For reasons unknown, executing 'write' with 0 bytes will hang the Aurora
parallel port - avoid it...
*/
#include <stdio.h>
#include <signal.h>
#include <errno.h>
enum FILETYPE { text, PCL, Postscript };
static enum FILETYPE mode;
static int psDup_off;
static int gs_pid;
void duplex_off(void)
{
#ifdef DUPLEX
char cmd[80];
if (mode == Postscript) {
if (!psDup_off) {
strcpy(cmd, "<< /Duplex false >> setpagedevice\n");
write(1, cmd, strlen(cmd));
psDup_off = 1;
}
} else
write(1, "\033&l0S", 5); /* duplex off */
#endif
}
/* when 'lprm' is executed, clean up the job before terminating.
*/
void sigint(int s)
{
#ifdef GHOSTSCRIPT
/* If postscript, we've started a subprocess to run gs which may
have gone away when a job is removed - just exit in this case,
so we don't hang on the write.
*/
if (mode == Postscript) {
if (gs_pid) kill(gs_pid, SIGINT);
exit(0);
}
#else
duplex_off();
write(1, "\033E", 2); /* reset */
#endif
exit(0);
}
void gs_sig(int s)
{
int n;
wait(&n); /* pick up gs subprocess exit status */
if ((n & 0xff) != 0) exit(-1);
else exit((n >> 8) & 0xff);
}
int main(int ac, char **av)
{
int nbytes, col, i, nb, n, sd[2];
char buff[307], *p, *s, *eob;
char cmd[80];
signal(SIGINT, sigint);
/* Get some characters, and determine its type */
nbytes = read(0, buff, sizeof(buff));
p = s = buff;
if ((nbytes > 0) && (buff[0] == '\033')) {
mode = PCL;
write(1, "\033E", 2);
/* Scan for initial \033E reset sequence at beginning of buffer.
This can turn off other modes (e.g., duplex) if sent later..
*/
if (buff[1] == 'E') s = &buff[2];
} else if ((nbytes >= 10) && !strncmp(buff, "%!PS-Adobe", 10)) {
mode = Postscript;
} else {
mode = text;
/* Check for first character ^L; omit since we're already at
top of form.
*/
if (*p == '\f') {
p++;
s = p;
}
write(1, "\033E", 2);
#ifdef LAND132
strcpy(cmd, "\033&l2A\033(s13H\033&l1O");
write(1, cmd, strlen(cmd));
#endif
}
#ifdef GHOSTSCRIPT
if (mode == Postscript) {
/* fork subprocess, make pipe, run 'hpps' script */
pipe(sd);
if (!(gs_pid = fork())) {
/* subprocess */
close(sd[1]);
dup2(sd[0], 0); /* pick up stdin */
if (execl("/usr/local/bin/hpps", "hpps", 0) < 0)
perror("can't exec /usr/local/bin/hpps");
exit(0);
} else {
dup2(sd[1], 1); /* pick up stdout */
/* we want to be notified of abnormal terminations, so we can
quit....
*/
signal(SIGCHLD, gs_sig);
}
}
#endif
#ifdef DUPLEX
if (mode == Postscript) {
/* Scan to end of first line; insert duplex command */
eob = &buff[nbytes];
while (p < eob) {
if (*p == '\n') {
p++;
write(1, buff, p - buff);
s = p;
strcpy(cmd, "<< /Duplex true >> setpagedevice\n");
write(1, cmd, strlen(cmd));
break;
} else p++;
}
} else {
write(1, "\033&l1S", 5); /* duplex, long edge binding */
}
#endif
col = 0;
do {
if (mode == text) {
/* expand tabs and add CR to LF */
for (eob = &buff[nbytes]; p < eob; i++, p++) {
switch (*p) {
/* Line feeds expand to CR LF */
case '\n':
n = p - s;
if (n > 0) write(1, s, n);
write(1, "\r\n", 2);
s = p + 1;
col = 0;
continue;
case '\r': col = 0;
break;
/* Tabs expand by 8
012345678901234567890
x x
*/
case '\t':
n = p - s;
if (n > 0) write(1, s, n);
nb = 8 - (col % 8);
write(1, " ", nb);
col += nb;
s = p + 1;
continue;
default: col++;
break;
}
}
#ifdef DUPLEX
} else if (mode == Postscript) {
/* Scan for %%EOF; put in end of duplex if found. Note that
if not found, p will equal &buff[nbytes], and entire buffer
will be written out, below.
*/
eob = &buff[nbytes];
for (p=buff; p<eob; p++) {
if (*p == '%') {
/* Check for enough chars to compare;
get more if need more */
if (eob - p < 5) {
n = p - s;
if (n > 0) write(1, s, n);
nbytes = eob - p;
memcpy(s, p, nbytes);
n = read(0, &buff[nbytes], sizeof(buff)-nbytes);
if (n < 0) break;
nbytes += n;
eob = &buff[nbytes];
p = buff;
}
if (eob - p >= 5 && !strncmp(p, "%%EOF", 5)) {
n = p - s;
if (n) write(1, s, n);
duplex_off();
s = p;
p = eob;
break;
}
}
}
#endif
} else {
/* PCL and non-Duplex Postscript modes are just pass thru */
p = &buff[nbytes];
}
/* Flush buffer */
n = p - s;
if (n > 0) write(1, s, n);
nbytes = read(0, buff, sizeof(buff));
p = s = buff;
} while (nbytes > 0);
duplex_off();
if (mode != Postscript)
write(1, "\033E", 2);
#ifdef GHOSTSCRIPT
close(sd[1]);
close(1);
if (mode == Postscript) {
/* wait for Ghostscript subprocess to terminate */
signal(SIGCHLD, SIG_DFL);
wait(&n);
if ((n & 0xff) != 0) return -1;
else return (n >> 8) & 0xff;
} else {
return 0;
}
#else
close(1);
return 0;
#endif
}
More information about the Discuss
mailing list