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