[net.sources.mac] laser - print/download file to Apple LaserWriter connected to non-Mac

matti@ttds.UUCP (Matti Rendahl) (02/10/86)

Here follows a program that lets you print plain textfiles on Apple LaserWriter
from a computer connected to the RS232 port of the LW. It also supplies
options to download a PostScript file, e.g. a TeX document processed by
dvi2ps. 

This version is developed and tested on a VAX11/750 running BSD4.2, but it
should not be to hard to get it running on other systems (I know it is 
running on VAX-VMS).

The program is not smart enough to let you choose font, slant, etc. (yet), but
it lets you choose between A4 and A6 format, header or no header, etc. All
output from the LaserWriter is read and printed to standardoutput.

It is also nice to use ``laser'' together with ``atprint'' supplied to the
net by Anders Hillbo.

-------------------------- C U T  H E R E -----------------------------
: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
echo 'Extracting INSTALL'
sed 's/^X//' > INSTALL << '+ END-OF-FILE INSTALL'
X
X``laser'' is developed and tested on a VAX 11/750 running BSD4.2, and is not
Xguaranteed to run on any other UNIXsystem. 
X
XIn order to get this program to run you must make a link ``/dev/laser'' to
Xthe tty your LaserWriter is connected to. An alternative is to alter the
Xdefinition of LASERPORT and LOCKFILE in ``laser.h''.
+ END-OF-FILE INSTALL
chmod 'u=rw,g=rw,o=r' 'INSTALL'
echo '	-rw-rw-r--  1 matti         324 Feb  9 17:20 INSTALL        (as sent)'
echo -n '	'
/bin/ls -l INSTALL
echo 'Extracting NOTES'
sed 's/^X//' > NOTES << '+ END-OF-FILE NOTES'
X
XIn the manualpage supplied a reference is made to a program called
X``atprint''. This is a spooler program written by Anders Hillbo at my
Xdepartement, and also supplied to USENET.
X
+ END-OF-FILE NOTES
chmod 'u=rw,g=rw,o=r' 'NOTES'
echo 'Diff in size can be ignored'
echo '	-rw-rw-r--  1 matti         178 Feb  9 17:28 NOTES        (as sent)'
echo -n '	'
/bin/ls -l NOTES
echo 'Extracting Makefile'
sed 's/^X//' > Makefile << '+ END-OF-FILE Makefile'
X#
X# Makefile 
X#
X
X# NOTE: The variable MAKEFILE *must* contain the actual name of the
X#       makefile. If not ``make depend'' will fail. So if you decide
X#       to alter the name of the makefile, be sure to set MAKEFILE
X#       to the new name!
XMAKEFILE=Makefile
X
XCSRCS=  laser.c
X
XOBJS=   laser.o
X
XLIBFILES=
X
XLIBS=
X
XDFLAGS=-DBSD42 
X
XCFLAGS=-O ${DFLAGS}
X
XLDFLAGS=
X
XRUNABLE=laser
X
XBINDIR=/usr/local
X
Xall: ${OBJS}
X	cc ${LDFLAGS} -o ${RUNABLE} ${OBJS} ${LIBS}
X
Xinstall: all
X	install -s ${RUNABLE} ${BINDIR}
X
Xclean:
X	rm -f ${OBJS} ${RUNABLE}
X
Xdepend: 
X	${CC} -M ${CSRCS} > makedep
X	echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
X	echo '$$r makedep' >>eddep
X	echo 'w' >>eddep
X	cp ${MAKEFILE} ${MAKEFILE}.bak
X	ex - ${MAKEFILE} < eddep
X	rm eddep makedep
X
X# DO NOT DELETE THIS LINE
Xlaser.o: laser.c
Xlaser.o: /usr/include/stdio.h
Xlaser.o: /usr/include/signal.h
Xlaser.o: /usr/include/sgtty.h
Xlaser.o: /usr/include/sys/ioctl.h
Xlaser.o: /usr/include/sys/ttychars.h
Xlaser.o: /usr/include/sys/ttydev.h
Xlaser.o: /usr/include/setjmp.h
Xlaser.o: /usr/include/sys/file.h
Xlaser.o: /usr/include/sys/time.h
Xlaser.o: ./laser.h
+ END-OF-FILE Makefile
chmod 'u=rw,g=rw,o=r' 'Makefile'
echo '	-rw-rw-r--  1 matti        1106 Feb  9 18:00 Makefile        (as sent)'
echo -n '	'
/bin/ls -l Makefile
echo 'Extracting laser.1'
sed 's/^X//' > laser.1 << '+ END-OF-FILE laser.1'
X.TH LASER 1 "3 September 1985"
X.SH NAME
Xlaser \- print file(s) on Apple LaserWriter
X.SH SYNOPSIS
X.B laser
X[
X.B \-d
X] [
X.B \-h
X] [
X.B \-ttitle
X] [
X.B \-l[ttyXX]
X] [
X.B \-a(4|6)
X] [
X.B file1 ... filen
X]
X.SH DESCRIPTION
X.I Laser
Xprints plain textfiles or PostScriptfiles on Apple LaserWriter.
XFor plain textfiles the format can be specified, with or without header.
XIf no file is specified `laser' takes it's input from stdin.
X.PP
X.B Options:
X.PP
X.TP
X.B \-d
XDownload. Takes a PostScriptfile and executes it in the LaserWriter. Could
Xbe used to print, e.g., TeX files (dvi2ps).
X.TP
X.B \-h
XHeader. Print header (ISO-day and time, filename and pageno) on each page.
X.TP
X.B \-t
XTitle. Print this on top of every page, sidenumber at bottom.
XIf both `-h' and `-t' is given, title will be used instead of ``filename'' 
Xin header.
X.TP
X.B \-l
XLine. Send the output from laser to /dev/ttyXX. If no argument is
Xgiven, the default is the tty that the command is typed in at (works
Xwell if you do it at a Mac running ``atprint''). If you don't have a
X/dev/laser on your system, but know to which tty the LaserWriter
Xis hooked up then you can use this option with an argument.
X.TP
X.B \-a(4|6)
XFormat. You can choose between A4 or A6. A6 will put 4 pages on every
Xprinted page.
X.PP
X.SH FILES
X/usr/spool/uucp/LCK..laser
X.br
X/usr/spool/uucp/LCK..ttyXX   if \-l option used.
X.SH SEEALSO
Xatprint(1)
X.SH BUGS
XIf the laserwriter is offline `laser' will fail without any diagnostics.
X.br
XThe lockfile (/usr/spool/uucp/LCK..laser) will sometimes not be removed, e.g.
Xif the process is killed with a signal that is not trapped.
X.SH AUTHOR
XMatti Rendahl (matti@bogart)
+ END-OF-FILE laser.1
chmod 'u=rw,g=rw,o=r' 'laser.1'
echo '	-rw-rw-r--  1 matti        1641 Feb  9 17:24 laser.1        (as sent)'
echo -n '	'
/bin/ls -l laser.1
echo 'Extracting laser.c'
sed 's/^X//' > laser.c << '+ END-OF-FILE laser.c'
X
X/*
X *	Copyright (c) 1986, Matti Rendahl <matti@bogart>
X *      
X *      This program may be copied for non-commercial use only, provided
X *      that any and all copyright notices are preserved.
X *      
X *      Please report bugs and/or fixes to:
X *
X * 	UUCP: {seismo,mcvax}!enea!ttds!bogart!matti
X * 	ARPA: enea!ttds!bogart!matti@seismo.ARPA
X *   	or    Matti_Rendahl_NADA%QZCOM.MAILNET@MIT-MULTICS.ARPA
X *
X */
X
X#include        <stdio.h>
X#include        <signal.h>
X#include        <sgtty.h>
X#include 	<setjmp.h>
X#include        <sys/file.h>
X#include	<sys/time.h>
X
X#include "laser.h"
X
Xchar    page[80][200],
X        lockfile[50],
X        laserport[25];
Xint     format,
X        tflag,
X        dflag,
X        hflag,
X        lflag,
X        rows,
X        cols;
XFILE * lasfp;
X
XFILE * infp;
Xint     father,
X        child;
Xint     die (), pause (), cont ();
Xint     rem;
X
Xchar    PS[] = "/Y %d def 1 1 %d {pop %d Y moveto show /Y Y %d add def}for\n";
Xchar    status[] = "\nclear \n(Processing %s) print (\n) print flush\n";
Xchar    header[160];
Xchar    title[160];
Xchar   *ttyline;
X
Xjmp_buf env;
X
Xstruct sgttyb   oldtty;
X
Xmain (argc, argv)
Xint     argc;
Xchar  **argv;
X{
X    FILE * fp;
X    char   *cp;
X
X    format = A4;
X    hflag = 0;
X    tflag = 0;
X    dflag = FALSE;
X    lflag = FALSE;
X    argv++;
X    while (**argv == '-') {
X	cp = *argv++;
X	switch (*++cp) {
X	    case 'a': 
X		cp++;
X		if (!*cp)
X		    cp = *argv++;
X		switch (*cp) {
X		    case '4': 
X			format = A4;
X			break;
X		    case '5': 
X			format = A5;
X			break;
X		    case '6': 
X			format = A6;
X			break;
X		    default: 
X			usage ();
X		}
X		break;
X	    case 'h': 
X		hflag = 1;
X		break;
X	    case 't': 
X		tflag = 2;
X		if (!*++cp)
X		    usage ();
X		else
X		    strcpy (title, cp);
X		break;
X	    case 'd': 
X		dflag = TRUE;
X		break;
X	    case 'l': 
X		lflag = TRUE;
X		if (!*++cp)
X		    ttyline = rindex (ttyname (0), '/') + 1;
X		else
X		    ttyline = cp;
X		break;
X	    default: 
X		usage ();
X	}
X    }
X    if (format == A5) {
X	fprintf (stderr, "laser: A5 not allowed yet.\n");
X	exit (2);
X    }
X    signal (SIGINT, closelaser);
X    signal (SIGTERM, closelaser);
X    signal (SIGQUIT, closelaser);
X    if (!openlaser ())
X	exit (2);
X    father = getpid ();
X    if ((child = fork ()) == 0) {
X	int     c;
X
X	fclose (lasfp);
X	signal (SIGINT, SIG_IGN);
X	signal (SIGHUP, die);
X	setbuf (stdout, NULL);
X	for (;;) {
X	    c = getc (infp);
X	    putchar (c);
X	}
X    }
X    signal (SIGHUP, pause);
X    fclose (infp);
X    if (dflag) {
X	if (argc == 1 || !*argv)
X	    download (stdin);
X	else
X	    while (*argv) {
X		if ((fp = fopen (*argv, "r")) == NULL) {
X		    fprintf (stderr, "laser: cannot open file %s\n", *argv);
X		    argv++;
X		    continue;
X		}
X		fprintf (lasfp, status, *argv);
X		download (fp);
X		fclose (fp);
X		argv++;
X	    }
X    }
X    else {
X	if (!initpage (format))
X	    exit (2);
X	if (argc == 1 || !*argv) {
X	    switch (tflag + hflag) {
X		case 1: 
X		    sprintf (header, "%s Page ", isodate ());
X		    break;
X		case 3: 
X		    sprintf (header, "%s %s Page ", isodate (), title);
X		    break;
X	    }
X	    printfile (stdin, format);
X	}
X	else {
X	    while (*argv) {
X		if ((fp = fopen (*argv, "r")) == NULL) {
X		    fprintf (stderr, "laser: cannot open file %s\n", *argv);
X		    argv++;
X		    continue;
X		}
X		fprintf (lasfp, status, *argv);
X		switch (tflag + hflag) {
X		    case 1: 
X			sprintf (header, "%s %s Page ", isodate (), *argv);
X			break;
X		    case 3: 
X			sprintf (header, "%s %s Page ", isodate (), title);
X			break;
X		}
X		printfile (fp, format);
X		fclose (fp);
X		argv++;
X	    }
X	}
X    }
X    closelaser ();
X}
X
Xinitpage (format)
Xint     format;
X{
X    rows = _rows[format];
X    cols = _cols[format];
X    return (OK);
X}
X
X
Xopenlaser () {
X    int     try;
X    struct sgttyb   remote;
X
X    strcpy (lockfile, LOCKFILE);
X    strcpy (laserport, LASERPORT);
X
X    if (lflag) {
X	register char  *p;
X
X	p = rindex (lockfile, '.');
X	*++p = '\0';
X	strcat (lockfile, ttyline);
X	p = rindex (laserport, '/');
X	*++p = '\0';
X	strcat (laserport, ttyline);
X    }
X
X    for (try = 0; try < 6; try++) {
X	if (open (lockfile, O_WRONLY | O_CREAT | O_EXCL, 0600) < 0) {
X	    if (try < 5) {
X		sleep (1);
X		continue;
X	    }
X	    fprintf (stderr, "Laser busy!\n");
X	    return (ERR);
X	}
X	break;
X    }
X
X    if ((rem = open (laserport, 2)) < 0) {
X	fprintf (stderr, "laser: cannot open laserwriter\n");
X	unlink (lockfile);
X	return (ERR);
X    }
X
X    gtty (rem, &remote);
X    oldtty = remote;
X    remote.sg_ispeed = remote.sg_ospeed = SPEED;
X    remote.sg_erase = remote.sg_kill = '\000';
X    remote.sg_flags = CBREAK + TANDEM;
X    stty (rem, &remote);
X    ioctl (rem, TIOCSDTR, 0);
X
X    if ((lasfp = fopen (laserport, "w")) == NULL ||
X	    (infp = fopen (laserport, "r")) == NULL) {
X	fprintf (stderr, "laser: cannot open laserwriter\n");
X	unlink (lockfile);
X	return (ERR);
X    }
X    putc ('\004', lasfp);
X    return (OK);
X}
X
Xinitlaser (x, y, size)
Xint     x,
X        y,
X        size;
X{
X    fprintf (lasfp, "\ninitmatrix\n");
X    fprintf (lasfp, "\n%d %d translate\n", x, y);
X    fprintf (lasfp, "\n/Courier findfont %d scalefont setfont\n", size);
X    return (OK);
X}
X
Xdie () {
X    exit (0);
X}
X
Xcont () {
X    signal (SIGHUP, pause);
X    longjmp (env, 1);
X}
X
Xpause () {
X    signal (SIGHUP, cont);
X    if (setjmp (env))
X	return;
X    for (;;)
X	sleep (240);
X}
X
Xcloselaser () {
X    putc ('\004', lasfp);
X    fflush (lasfp);
X    stty (fileno (lasfp), &oldtty);
X    fclose (lasfp);
X    unlink (lockfile);
X    kill (child, SIGHUP);
X    exit (0);
X}
X
Xdownload (fp)
XFILE * fp;
X{
X    int     ch;
X
X    while ((ch = getc (fp)) != EOF)
X	putc (ch, lasfp);
X}
X
Xprintfile (fp, format)
XFILE * fp;
Xint     format;
X{
X    int     i,
X            count,
X            subpage = 0,
X            showpage = 0,
X            pageNo = 1;
X
X    while ((count = makepage (fp, format))) {
X	switch (format) {
X	    case A4: 
X		initlaser (40, 0, _size[format]);
X		for (i = 0; i < count; i++) {
X		    fprintf (lasfp, "(%s)\n", page[i]);
X		}
X		fprintf (lasfp, PS,
X			A4MAXY - count * A4SIZE + A4SIZE, count, 30, A4SIZE);
X		switch (tflag + hflag) {
X		    case 1: 
X		    case 3: 
X			putheader (190 - strlen (header) / 2,
X				A4MAXY + 2 * A4SIZE, pageNo++);
X			break;
X		    case 2: 
X			puttitle (210 - strlen (title) / 2,
X				A4MAXY + 2 * A4SIZE, pageNo++);
X			break;
X		}
X		fprintf (lasfp, "\nshowpage\n");
X		break;
X	    case A5: 
X		break;
X	    case A6: 
X		showpage = 1;
X		initlaser (40, 0, _size[format]);
X		for (i = 0; i < count; i++) {
X		    fprintf (lasfp, "(%s)\n", page[i]);
X		}
X		subpage = subpage == 4 ? 1 : subpage + 1;
X		switch (subpage) {
X		    case 1: 
X			fprintf (lasfp, PS, A6MAXY - count * A6SIZE + A6SIZE,
X				count, 30, A6SIZE);
X			break;
X		    case 2: 
X			fprintf (lasfp, PS,
X				A6MAXY - A6SIZE * A6ROWS -
X				count * A6SIZE - 10 * A6SIZE,
X				count, 30, A6SIZE);
X			break;
X		    case 3: 
X			fprintf (lasfp, PS, A6MAXY - count * A6SIZE + A6SIZE,
X				count, 60 * A6SIZE, A6SIZE);
X			break;
X		    case 4: 
X			fprintf (lasfp, PS,
X				A6MAXY - A6SIZE * A6ROWS -
X				count * A6SIZE - 10 * A6SIZE,
X				count, 60 * A6SIZE, A6SIZE);
X			break;
X		}
X		if (subpage == 4) {
X		    showpage = 0;
X		    switch (tflag + hflag) {
X			case 1: 
X			case 3: 
X			    putheader (250 - strlen (header) / 2,
X				    A6MAXY + 2 * A6SIZE, pageNo++);
X			    break;
X			case 2: 
X			    puttitle (250 - strlen (title) / 2,
X				    A6MAXY + 2 * A6SIZE, pageNo++);
X			    break;
X		    }
X		    fprintf (lasfp, "\nshowpage\n");
X		}
X		break;
X	}
X    }
X    if (showpage) {
X	switch (tflag + hflag) {
X	    case 1: 
X	    case 3: 
X		putheader (250 - strlen (header) / 2,
X			A6MAXY + 2 * A6SIZE, pageNo++);
X		break;
X	    case 2: 
X		puttitle (250 - strlen (title) / 2,
X			A6MAXY + 2 * A6SIZE, pageNo++);
X		break;
X	}
X	fprintf (lasfp, "\nshowpage\n");
X    }
X    return (OK);
X}
X
Xint     makepage (t, format)
X        FILE * t;
Xint     format;
X{
X    int     row,
X            col,
X            count,
X            c,
X            i;
X    char   *cp;
X
X    for (row = 0; row < rows; row++) {
X	cp = page[row];
X	col = 0;
X	while (col < cols && (c = getc (t)) != '\n') {
X	    switch (c) {
X		case '\f': 
X		    if (row == 0) {
X			*cp = '\0';
X			cp = page[row];
X			row++;
X			cp = page[row];
X		    }
X		case EOF: 
X		    *cp = '\0';
X		    return (row);
X		case '\t': 
X		    do {
X			*cp++ = ' ';
X			col++;
X		    } while (col & 07 && col < cols);
X		    break;
X		case '(': 
X		case ')': 
X		case '\\': 
X		    *cp++ = '\\';
X		default: 
X		    *cp++ = c;
X		    col++;
X		    break;
X	    }
X	}
X	*cp = '\0';
X    }
X    return (row);
X}
X
Xusage () {
X    fprintf (stderr,
X	    "usage: laser [-d] [-h] [-ttitle] [-l[ttyXX]] [-a(4|6)] [file1 ... filen]\n");
X    exit (2);
X}
X
Xchar   *isodate () {
X    static char date[40];
X    struct timeval  tv;
X    struct timezone tz;
X    struct tm  *st;
X    char   *ap;
X
X    extern long time ();
X    extern char *asctime ();
X    extern struct tm   *localtime ();
X
X    gettimeofday (&tv, &tz);
X    time (&tv.tv_sec);
X    st = localtime (&tv.tv_sec);
X    ap = asctime (st);
X    sprintf (date, "%.4s%4d-%02d-%02d %02d:%02d:%02d\0",
X	    ap,
X	    st -> tm_year + 1900,
X	    st -> tm_mon + 1,
X	    st -> tm_mday,
X	    st -> tm_hour,
X	    st -> tm_min,
X	    st -> tm_sec);
X    return (date);
X}
X
Xputheader (x, y, n)
Xint     x,
X        y,
X        n;
X{
X    fprintf (lasfp, "(%s%d)", header, n);
X    fprintf (lasfp, "%d %d moveto show\n", x, y);
X}
X
Xputtitle (x, y, n)
Xint     x,
X        y,
X        n;
X{
X    fprintf (lasfp, "(%s)", title);
X    fprintf (lasfp, "%d %d moveto show\n", x, y);
X    fprintf (lasfp, "270 5 moveto (%d) show\n", n);
X}
+ END-OF-FILE laser.c
chmod 'u=rw,g=rw,o=r' 'laser.c'
echo '	-rw-rw-r--  1 matti        9456 Feb  9 17:19 laser.c        (as sent)'
echo -n '	'
/bin/ls -l laser.c
echo 'Extracting laser.h'
sed 's/^X//' > laser.h << '+ END-OF-FILE laser.h'
X
X/*
X *	Copyright (c) 1986, Matti Rendahl <matti@bogart>
X *      
X *      This program may be copied for non-commercial use only, provided
X *      that any and all copyright notices are preserved.
X *      
X *      Please report bugs and/or fixes to:
X *
X * 	UUCP: {seismo,mcvax}!enea!ttds!bogart!matti
X * 	ARPA: enea!ttds!bogart!matti@seismo.ARPA
X *   	or    Matti_Rendahl_NADA%QZCOM.MAILNET@MIT-MULTICS.ARPA
X *
X */
X
X#define OK      1
X#define ERR     0
X#define TRUE    -1
X#define FALSE   0
X
X#define LASERPORT       "/dev/laser"
X#define LOCKFILE        "/usr/spool/uucp/LCK..laser"
X#define SPEED           B9600
X
X#define A4      1
X#define A5      2
X#define A6      3
X
X#define A4SIZE  10
X#define A5SIZE  10
X#define A6SIZE  5
X
X#define A4MAXY  730
X#define A5MAXY  0
X#define A6MAXY  730
X
X#define A4ROWS  70
X#define A5ROWS  64
X#define A6ROWS  64
X
X#define A4COLS  81
X#define A5COLS  77
X#define A6COLS  81
X
Xint     _size[4] = {
X    0, A4SIZE, A5SIZE, A6SIZE
X};
X
Xint	_rows[4] = {
X    0, A4ROWS, A5ROWS, A6ROWS
X};
X
Xint	_cols[4] = {
X    0, A4COLS, A5COLS, A6COLS
X};
X
Xint     closelaser ();
Xchar	*isodate () ;
Xchar	*getenv () ;
Xchar	*rindex () ;
Xchar	*ttyname () ;
+ END-OF-FILE laser.h
chmod 'u=rw,g=rw,o=r' 'laser.h'
echo '	-rw-rw-r--  1 matti        1151 Feb  9 17:48 laser.h        (as sent)'
echo -n '	'
/bin/ls -l laser.h
exit 0

--------
   	        Matti Rendahl, CVAP, RIT    <matti@bogart>
	Computer Vision and Associative Pattern processing laboratory
  	    Department of Numerical Analysis and Computer Science
	            The Royal Institute of Technology

 UUCP: {seismo,mcvax}!enea!ttds!matti         ARPA: enea!ttds!matti@seismo.ARPA