Summary: Printing via parallel to HP LaserJet 4M Plus

From: Joe Fedock (jfedock@motown.ge.com)
Date: Mon Feb 20 1995 - 23:14:29 CST


Thanks to the following for their responses:

Lawrence A. Bilker <bilkerla@pluto.crd.ge.com >
Linda Cygan <cygan@wpm.com>
Michael Baumann <baumann@proton.llumc.edu>
Michael R. Zika <zika@trinity.tamu.edu>
Olav Lerbrekk <olav.lerbrekk@geologi.uio.no>
Todd Pfaff <todd@immrc.eng.McMaster.CA>

Most responded that HP's jetadmin software is available from
HP's ftp site (ftp-boi.external.hp.com:/pub/jetdirect/<os>) and
the readme file there contains directions. This is true and
I got the jetadmin software. However, jetadmin does not support
printing to a directly connected printer and requests an
IP address for the printer during installation. Michael Baumann
creatively suggested that I modify the jetadmin software to use the
contained filters and let the output drop back to standard
output instead of directing it to hpnpf. This I failed to get
to work however.

The answer that got me up and running was from Todd Pfaff.
He sent me a printcap entry, shell script wrapper,
lj4m C code, and a uuencoded copy of the lj4m binary.
I simply uudecoded the binary, dropped that and the shell script
into place (with appropriate minor changes), modified
printcap and it worked. The lj4m software that Todd sent
was originally written by Michael A. Covington and Mark L. Juric.
Todd modified it to support PostScript print jobs generated by software
that outputs Apple LaserWriter Postscript jobs (that do NOT begin
with %! -- in which case he detects 'statusdist begin').

I'll enclose his example printcap entry, the shell script wrapper,
and his modified lj4m.c here, for your reference. My original question
to sun-managers follows that. Should anyone need it, upon request,
I can also send the uuencoded lj4m binary for sun4.

Thanks all.

Joseph M. Fedock (voice) 609 722-4799
IIS Tech Services (pager) 609 342-9014
Martin Marietta jfedock@motown.ge.com
Government Electronic Systems
Mail Stop 104-036
199 Borton Landing Road
P.O. Box 1027
Moorestown, NJ 08057-0927
--------------------------------------------------------------------------------
<BEGIN /etc/printcap>
 
JHE115lj|ps|text|HP LaserJet in JHE 115A:\
        :if=/usr/local/etc/lpd/JHE115lj.if:\
        :lf=/var/adm/lpd-errs:\
        :lp=/dev/bpp0:\
        :mx#0:\
        :sd=/var/spool/JHE115lj:\
        :sh:
 
--------------------------------------------------------------------------------
<BEGIN /usr/local/etc/lpd/JHE115lj.if>
 
#!/bin/sh
 
# find the printername
cwd=`pwd`
pname=`basename $cwd`
 
LOG=$cwd/log
 
# Find the user and host name, other parameters not used.
 
while test $# != 0
do case "$1" in
  -c) ;;
  -w*) width=$1 ;;
  -l*) length=$1 ;;
  -i*) indent=$1 ;;
  -x*) width=$1 ;;
  -y*) length=$1 ;;
  -n) user=$2 ; shift ;;
  -n*) user=`expr $1 : '-.\(.*\)'` ;;
  -h) host=$2 ; shift ;;
  -h*) host=`expr $1 : '-.\(.*\)'` ;;
  -*) ;;
  *) afile=$1 ;;
  esac
  shift
done
 
exec /usr/local/etc/lpd/lj4m $user $host
 
-------------------------------------------------------------------------------
<BEGIN lj4m.c>
 
/*
   lj4m.c -- Michael A. Covington and Mark L. Juric, 1994
   Pre-spooler filter for LaserJet 4M.
   Compile with gcc or ANSI C.
   Install with the "if=" (not "of=") option in /etc/printcap.
   Print jobs are logged as lpr.debug messages.
 
   modified by Todd Pfaff (todd@water.eng.mcmaster.ca) 02/02/95
*/
 
#include <syslog.h>
#include <stdio.h>
#include <string.h>
 
#define CTRLD "\004"
#define LINELENGTH 80
 
/*** HP LaserJet control sequences ***/
 
#define RESET "\033E"
#define LF_TO_CRLF "\033&k2G"
#define LMARGIN "\033&a11L"
#define FONT "\033(s0p(s12h(s4b(s4099T"
#define START_PJL "\033%-12345X@PJL\n"
#define END_PJL "\033%-12345X"
#define POSTSCRIPT "@PJL ENTER LANGUAGE = POSTSCRIPT\n"
#define PCL "@PJL ENTER LANGUAGE = PCL\n"
 
 
/*** Global variables ***/
 
char first[1024]; /* first 1024 characters of file */
int nfirst; /* length of first characters */
char c;
long int bytes; /* character count */
char userinfo[64] = ""; /* will be "machine:username" */
 
 
/*** Printer console display functions ***/
 
void DisplayOnPrinterConsole(char *s)
{
        fprintf(stdout,"%s%s%s%s%s%s%s",
                        RESET,
                        START_PJL,
                        "@PJL RDYMSG DISPLAY = \"",
                        s,
                        "\"\n",
                        END_PJL,
                        RESET);
}
 
void ResetPrinterConsole() /* to display "00 READY" */
{
        fprintf(stdout,"%s%s%s%s%s",
                        RESET,
                        START_PJL,
                        "@PJL RDYMSG DISPLAY = \"\"\n",
                        END_PJL,
                        RESET);
}
 
 
/*** PostScript and HP file handling ***/
 
void PrintPostScriptFile(suspect)
        int suspect;
{
        /* Choose language */
        fprintf(stdout,"%s%s%s",RESET,START_PJL,POSTSCRIPT);
 
        /* Transmit file transparently */
        for(bytes=0; ; bytes++)
        {
                if(bytes < nfirst)
                        c = first[bytes];
                else
                {
                        c = getc(stdin);
                        if(feof(stdin)) break;
                }
 
                putc(c,stdout);
        }
 
        /* Add newline, Ctrl-D, and reset at end */
        fprintf(stdout,"\n%s%s%s",CTRLD,END_PJL,RESET);
 
        /* Log results */
        syslog(LOG_DEBUG,"%s, PostScript file%s, %d bytes",
                suspect?" (suspect)":"",userinfo,bytes);
}
 
 
void PrintHPFile()
{
        /* Choose language */
        fprintf(stdout,"%s%s%s",RESET,START_PJL,PCL);
 
        /* Transmit file transparently */
        for(bytes=0; ; bytes++)
        {
                if(bytes < nfirst)
                        c = first[bytes];
                else
                {
                        c = getc(stdin);
                        if(feof(stdin)) break;
                }
 
                putc(c,stdout);
        }
 
        /* Reset printer at end */
        fprintf(stdout,"%s%s",END_PJL,RESET);
 
        /* Log results */
        syslog(LOG_DEBUG,"%s, HP file, %d bytes",userinfo,bytes);
}
 
 
/*** ASCII and unprintable file handling ***/
 
#define PRINTABLE(c) (printable[(unsigned char) c])
 
char printable[256] =
/* Table of which ASCII codes are printable characters */
{
        0,0,0,0,1,0,0,1,1,1,1,0,1,1,0,0, /* NUL to ^O */
        0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, /* ^P to 31 */
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 32 to 47 */
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 48 to 63 */
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 64 to 79 */
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 to 95 */
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 96 to 112 */
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, /* 113 to 127 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128 to 143 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144 to 159 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160 to 175 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176 to 191 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192 to 207 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208 to 223 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224 to 239 */
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }; /* 240 to 255 */
/* -1 (eof) maps onto 255 */
 
 
void PrintASCIIFile()
{
        int position = 1; /* where the next char on the line will be */
        int j;
 
        /* Set up printer */
        fprintf(stdout,"%s%s%s%s%s%s",
                        RESET,
                        START_PJL,
                        PCL,
                        LF_TO_CRLF,
                        FONT,
                        LMARGIN);
 
        /* Process rest of file, breaking at column 80 and
           underlining last character if line continues beyond */
 
        for(bytes=0; ; bytes++)
        {
                if(bytes < nfirst)
                        c = first[bytes];
                else
                {
                        c = getc(stdin);
                        if(feof(stdin)) break;
                }
 
                /* If a bad byte was found, print messages and dump */
                if(!PRINTABLE(c))
                {
                        /* Set up printer again because it may have been disrupted */
                        fprintf(stdout,"\n%s%s%s%s%s%s",
                                        RESET,
                                        START_PJL,
                                        PCL,
                                        LF_TO_CRLF,
                                        FONT,
                                        LMARGIN);
 
                        /* Dump 30 lines, printing '.' for unprintable characters */
                        fprintf(stdout,
                                        "%s\nUnprintable data! Partial dump follows...\n",
                                        userinfo);
 
                        for(j=1; j<=(LINELENGTH*30); j++)
                        {
                                if(bytes < nfirst)
                                        c = first[bytes++];
                                else
                                {
                                        c = getc(stdin);
                                        if(feof(stdin)) break;
                                }
 
                                if (c<32 || c>126) c = '.';
                                fputc(c,stdout);
                                if (j % LINELENGTH == 0) fputc('\n',stdout);
                        }
 
                        /* Reset printer at end */
                        fprintf(stdout,"%s%s",END_PJL,RESET);
 
                        /* Log the error */
                        syslog(LOG_ERR,
                                   "LJ4M: %s: tried to print unprintable data\n",userinfo);
 
                        return;
                }
 
                if (c==4 || c==26) break; /* Skip UNIX or DOS EOF mark */
 
                /* Compute where c will print */
                if (c==10 || c==12 || c==13) position=0; /* CR, FF, or LF */
                else if (c==8 && position>0) position--; /* Backspace */
                else position++;
 
                /* If in a printable column, print it */
                if (position <= LINELENGTH) fputc(c,stdout);
 
                /* If we have just run past margin, underline last character */
                if (position == LINELENGTH+1) fputs("\b_",stdout);
        }
 
        /* Reset printer at end */
        fprintf(stdout,"%s%s",END_PJL,RESET);
 
        /* If normal termination, report results */
        syslog(LOG_DEBUG,"%s, ASCII file, %d bytes",userinfo,bytes);
}
 
 
/*** Main program ***/
 
main(int argc, char* argv[])
{
        /* Obtain machine name and user name from cmd line args */
 
        if (argc>2)
                sprintf(userinfo,"%s@%s",argv[1],argv[2]);
        else
                sprintf(userinfo,"%d Unknown username", argc);
 
        DisplayOnPrinterConsole(userinfo);
 
        openlog("LaserJet 4M",0,LOG_LPR);
 
        /* Examine first 2 bytes, decide how to handle file */
 
        /* skip any leading CTRL-Ds or other non-escape control characters */
        nfirst=0;
        do
                first[nfirst++] = getc(stdin);
        while(first[nfirst-1] != 27 && !isprint(first[nfirst-1]) && !feof(stdin));
        first[nfirst++] = getc(stdin);
 
        /*
           check for special cases
           known rogues:
           Freelance - no leading %! on Apple LaserWriter Postscript jobs
           */
        if(first[nfirst-2]=='s' && first[nfirst-1]=='t')
        {
                char *s = "statusdict begin";
                int j = 1;
 
                while(s[j] != 0 && first[nfirst-1] == s[j] && !feof(stdin))
                {
                        first[nfirst++] = getc(stdin);
                        j++;
                }
 
                if(s[j] == 0)
                {
                        nfirst -= j+1;
                        first[nfirst++] = '%';
                        first[nfirst++] = '!';
                        first[nfirst++] = '\n';
                        for(j=0; j<strlen(s); j++)
                                first[nfirst++] = s[j];
                        first[nfirst++] = '\n';
                        PrintPostScriptFile(1);
                }
                else
                        PrintASCIIFile();
        }
        else if (first[nfirst-2]=='%' && first[nfirst-1]=='!')
                PrintPostScriptFile(0);
        else if (first[nfirst-2]==27
                         && (first[nfirst-1]=='E' || first[nfirst-1]=='%'))
                PrintHPFile();
        else
                PrintASCIIFile();
  
        /* Clean up */
        ResetPrinterConsole();
        closelog();
        return(0); /* UNIX insists on return code 0. */
}

--------------------------------------------------------------------------------
<BEGIN original message>

I thought I would never have to do this, but I'm desperate.
I never thought I'd have to ask for a printcap but I'm getting
down to the last straws already and have no solution in sight.

I have an HP Laserjet 4M Plus that I'm trying to drive
from a Sparc 20 via a parallel cable (Sun supplied cable).
I need to be able to print both straight ascii text and
postscript seamlessly. Unfortuately, I believe
the solution to my problems lies in HP's JetAdmin software,
but my customer won't buy it.

So, I have tried many things, but none of them work
successfully. I found an old copy of transcript
lying around and tried using that, but I can only
get it to print postscript. Ascii comes out blank
pages. I found a copy of cat and tried using
that to convert ascii to ps, but that fails
in the same way (blank pages out with ascii in).

I investigated a copy of Printcap City I have
with a date of May 28, 1993 on it (Volume VIb),
and tried the input and output filters specified therein
for various earlier versions of HP Laserjets, but
to no avail.

The best I could narrow the printcap file down to is
shown below (taken from my attempt at getting transcript
to work). I found the fc and xc arguments from a generic
parallel setup in a Sunsoft document for another piece of
hardware that is not related to the problem. The printer
will not even print postscript without them. As usual,
my search for specific information on these mask settings
turned up nothing I could readily use to solve the problem.

Any help on printcaps for this printer driven from a
parallel port would be greatly appreciated.

lp|lp|HP Laserjet 4M Plus:\
        :lp=/dev/bpp0:sd=/usr/spool/lpd:\
        :lf=/usr/spool/lpd/log:af=/usr/adm/lw.acct:\
        :tr=\f:fc#0177777:xc#0177777:\
        :mx#0:sf:sb:\
        :if=/usr/local/tran/sparc/lib/psif:\
        :of=/usr/local/tran/sparc/lib/psof:gf=/usr/local/tran/sparc/lib/psgf:\
        :nf=/usr/local/tran/sparc/lib/psnf:tf=/usr/local/tran/sparc/lib/pstf:\
        :rf=/usr/local/tran/sparc/lib/psrf:vf=/usr/local/tran/sparc/lib/psvf:\
        :cf=/usr/local/tran/sparc/lib/pscf:df=/usr/local/tran/sparc/lib/psdf:

Thanks, and I will summarize.

<END original message>
--------------------------------------------------------------------------------



This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:10:16 CDT