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