clewis@mnetor.UUCP (03/12/85)
I noticed a few days ago that several people were running into the annoyance that the laserjet creates an output bin of backwards printout. Some people are using special rearrangements of the output bin to cause the pages to flip over when printing (ugh). I have written an lp (att line printer spooler) filter that reverses the order of pages. Basically, it reads standard input writes the output to a temp file, remembering where the start of each page was. Then, it rereads the temp file in reverse-page-order (using seeks) to write the file to stdout. In addition, the filter provides the capability to place arbitrary HP control sequences at the beginning of each page (lines starting with \001). The filter shell (the second part of this shar file) gives an example of how it can be used. The filter shell was not written by me (I don't know where it came from, I suspect netnews). I have modified it extensively from the orignal to support the new filter (and next paragraph). The filter supports landscape mode too (A font cartridge). The filter shell also solves another grievance I'm sure that some people are having - page height. By default, the laser uses the standard 6 lines per inch, but since the laser uses 1/2 inch on all margins, you only get 60 lines per page. The filter shell issues appropriate top-of-page commands to change the line spacing so that (even in landscape mode) you get precisely 66 lines per page. Please let me know if you find any bugs. Note: the banner page is always right-side-up in 66 lines per page mode. Subsequent pages can be anything you want. Note: this is in production on a Pyramid, System V universe and on a VME10 running UNIX V/68. #!/bin/sh echo 'Start of pack.out, part 01 of 01:' echo 'x - laserfilter.c' sed 's/^X//' > laserfilter.c << '/' X/* X Laser filter - reverses page order. Takes standard X input and reverses page order to place on standard output. X Any line beginning with a ^A denotes a control sequence X to be emitted at the beginning of each subsequent page. X -t gives debugging output. X X*/ Xstatic char SrcId[] = "%Z% %M%:%I%"; X#include <stdio.h> X#include <string.h> X X#define FF 0x0c X#define PAGCONT 001 X#define LPERPAG 66 /* change if you fiddle around with page lengths */ X#define MAXLEN 5120 /* maximum line length */ Xtypedef struct line_desc { X long ld_offset; X char *ld_pagcntrl; X long ld_count; X struct line_desc *ld_prev; X} LD; X Xchar *Progname; X XLD *last = NULL; Xchar buf[MAXLEN]; X XLD *LDalloc(); X Xmain(argc, argv) Xint argc; Xchar **argv; { X FILE *f; X register LD *p; X register long offset; X register short recvd; X register int lines_pg = LPERPAG; X register char *ffp; X char *oldpagcntrl = NULL; X char *pagehdr = NULL; X char *malloc(); X int debugFlag = 0; X Progname = argv[0]; X if (argc >= 2 && strcmp(argv[1], "-t") == 0) { X argv++; X argc--; X debugFlag = 1; X } X strcpy(buf, ""); X f = tmpfile(); X offset = 0; X recvd = fgets(buf, sizeof(buf), stdin) != 0; X p = LDalloc(); X while(recvd && buf[0]) { X ffp = NULL; X /* if the line is a page control line ... */ X if (buf[0] == PAGCONT) { X int ctrllen; X ctrllen = strlen(buf); X if (buf[ctrllen-1] == '\n') buf[ctrllen-1] = '\0'; X /* remember page control for this and subsequent X pages */ X p->ld_pagcntrl = malloc(ctrllen); X if (!p->ld_pagcntrl) { X fprintf(stderr, "Could not allocate control\n"); X exit(1); X } X strcpy(p->ld_pagcntrl, buf+1); X oldpagcntrl = p->ld_pagcntrl; X goto nextline; /* sorry! */ X } X if ((ffp = strchr(buf, FF)) || p->ld_count == lines_pg) { X p = LDalloc(); X p->ld_pagcntrl = oldpagcntrl; X /* if (ffp) => we found a FF. We break the line X into two parts: X 1) before the FF - if any, we write it out X terminated with a new-line and increment X previous page's line count. X 2) after the FF: copy it into "buf" and X do this whole thing again. X Note: the FF is deleted, and explicitly emitted X during output phase */ X if (ffp) { X register char *cp = buf; X X /* calculate offset of first character past X FF in output file - beginning of new page */ X offset = p->ld_offset = offset + ffp - buf; X X /* copy out first part of line, if any */ X while(cp < ffp) fputc(*cp++, f); X X /* if there was something before the X FF, increment count of previous page and X output a newline to terminate reread. X update both cur-page and total offset X to reflect the fact that we added a char. X */ X if (ffp != buf) { X p->ld_prev->ld_count++; X fputc('\n', f); X offset++; X p->ld_offset++; X } X X /* copy the tail of the buffer over and X do this all again */ X strcpy(buf, ffp+1); X continue; X } else { X p->ld_offset = offset; X p->ld_count = 1; X } X } else X p->ld_count++; X offset += strlen(buf); X fputs(buf, f); X nextline: X recvd = fgets(buf, sizeof(buf), stdin) != 0; X } X while(p) { X register int len = p->ld_count; X fseek(f, p->ld_offset, 0); X if (p->ld_count == 0) X goto skipit; X if (debugFlag) { X printf("offset: %ld count: %ld\n", p->ld_offset, X p->ld_count); X if (p->ld_pagcntrl) X printf("control: %s\n", p->ld_pagcntrl); X } X if (len > 0 && p->ld_pagcntrl) X fputs(p->ld_pagcntrl, stdout); X while (--len >= 0) { X fgets(buf, sizeof(buf), f); X fputs(buf, stdout); X if (debugFlag) X break; X } X if (p->ld_count < lines_pg) X putc(FF, stdout); X skipit: X p = p->ld_prev; X } X exit(0); X} X XLD * XLDalloc() { X register LD *p; X extern char *malloc(); X p = (LD *) malloc(sizeof(LD)); X if (!p) { X fprintf("%s: cannot allocate memory\n", Progname); X exit(1); X } X if (last == NULL) { X last = p; X p->ld_prev = NULL; X } else { X p->ld_prev = last; X last = p; X } X p->ld_pagcntrl = NULL; X p->ld_offset = 0; X p->ld_count = 0; X return(p); X} X / echo 'x - laserjet' sed 's/^X//' > laserjet << '/' X# lp interface for hp 2686A laserjet printer X# X# Modified for use with reversal filter by: X# Chris Lewis, Mar 12, 1985 X# X# If the filter is not executable, then this interface will disable X# the lp printer which it was called to service. X# X# The following options are recognized: X# -f Use the 450 filter. X# -b Don't print a banner page. X# -c Use compressed print. X# -e Use expanded print. X# -l Use landscape instead of portrait mode. X# -p Don't do any filtration/settings X# X Xx="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" Xprinter=`basename $0` Xfilter=/usr/lib/laserfilter Xbanner=on Xexpand=off Xcompress=off Xlandscape=off Xreverse=on Xfor i in $5 Xdo Xcase "$i" in X b | -b) banner=off X ;; X c | -c) compress=on X ;; X e | -e) expand=on X ;; X f | -f) filter=/usr/bin/450 X reverse=off X ;; X l | -l) landscape=on X ;; X p | -p) filter=/bin/cat X reverse=off X ;; Xesac Xdone Xif [ -n "$filter" -a ! -x $filter ] Xthen X disable -r"can't execute $filter filter" $printer X exit 1 Xfi Xstty 9600 -tabs -parenb -cstopb cs8 istrip cread opost onlcr ixon -ixany ff0 cr0 nl0 0<&1 X Xtabs -0 X( Xif [ "$reverse" = "on" ] Xthen X echo "\001\c" # issue filter command Xfi Xecho "\033E\c" # Reset printer Xecho "\033&l66P\c" # Page length of 66 lines Xecho "\033&l2E\c" # Top margin of 2 lines Xecho "\033&l7.6C\c" # Vertical motion index of 7.6 Xecho "\033&l66F\c" # Text length of 66 lines Xif [ "$reverse" = "on" ] Xthen X echo # terminate filter command Xfi Xif [ "$banner" = "on" ] Xthen X echo "$x\n$x\n$x\n$x\n" X banner "$2" X echo "\n" X user=`grep "^$2:" /etc/passwd | line | cut -d: -f5` X if [ -n "$user" ] X then X echo "User: $user\n" X else X echo "\n" X fi X echo "Request id: $1 Printer: $printer\n" X date X echo "\n" X if [ -n "$3" ] X then X banner $3 X fi X echo "\014\c" Xfi Xif [ "$reverse" = "on" -a "${landscape}${compress}${expand}" != "offoffoff" ] Xthen X echo "\001\c" # Turn on filter page control X echo "\033E\c" # Reset printer Xfi Xif [ "$landscape" = "on" ] Xthen X echo "\033&l1O\c" # Turn on landscape mode X# Set up page X echo "\033&l66P\c" # Page length of 66 lines X echo "\033&l2E\c" # Top margin of 2 lines X echo "\033&l5.4545C\c" # Vertical motion index of 5.4545 X echo "\033&l66F\c" # Text length of 66 lines X# Select font: X echo "\033(8U\c" # Roman-8 X echo "\033(s0p16.66h8.5v0s-1b0T\c" X # Previous gobbledegook was: X # Primary font fixed spacing (s0p) X # 16.66 pitch (16.66h) X # 8.5/72" vertical spacing (8.5v) X # "light -1" (-1b) X # lineprinter (0T) Xfi Xif [ "$expand" = "on" ] Xthen X echo "\033(5H\c" Xfi Xif [ "$compress" = "on" ] Xthen X echo "\033(16H\c" Xfi Xif [ "$reverse" = "on" -a "${landscape}${compress}${expand}" != "offoffoff" ] Xthen X echo # Turn off filter page control Xfi Xcopies=$4 Xshift; shift; shift; shift; shift Xfiles="$*" Xi=1 Xwhile [ $i -le $copies ] Xdo X for file in $files X do X cat "$file" 2>&1 X echo '\014\c' X done X i=`expr $i + 1` Xdone X) | $filter Xerrcode=$? Xif [ $errcode -ne 0 ] Xthen X disable -r"error code $errcode from $filter filter" $printer X exit 1 Xfi Xexit 0 / echo 'Part 01 of pack.out complete.' exit -- Chris Lewis, Motorola New Enterprises SNail: 560 Dennison, Unit 9, Markham, Ontario, Canada, L3R 2M8 UUCP: {allegra, linus, ihnp4}!utzoo!utcs!mnetor!clewis BELL: (416)-475-1300 ext. 321