/* LaserJet print driver for Post V1.5. File "postlj.c" * (C) Adrian Aylward 1990, 1991 * * You may freely copy, use, and modify this file. * * This program prints PostScript files to a LaserJet. It sends the output * to the PAR: handler. Page size and orientation are read from the command * line. There are no printer status checks; if the output hangs check your * printer is ready. It is totally Amiga specific. * * The program was tested using Lattice C V5.05. It has various Lattice * dependencies. */ # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include "postlib.h" /* Assembler routines */ extern void insertbreak(void); extern void deletebreak(void); extern void insertftrap(void); extern void deleteftrap(void); /* Routines defined and referenced only within this module */ extern int strtoint(char **sp, int *ip); extern void __saveds __asm copypage(register __d0 int num); extern void prtsetup(void); extern void prtreset(void); extern void prtdump(int copies); extern void prtdumpline(char *buf, int len); /* Lattice startup */ extern struct UFB _ufbs[]; /* External data (initialised to zero) */ int retcode; int arec; BPTR errfh; FILE *parfp; struct library *PSbase; struct PSparm parm; int breakset, ftrapset; /* Options */ # define DEFSIZE 3 /* A4 page size */ # define DEFLAND 0 /* Portrait orientation */ # define DEFCOMP 1 /* Allow graphics compression (LJ2P etc.) */ # define MAXSIZE 8 int optsize = DEFSIZE; int optland = DEFLAND; int optcomp = DEFCOMP; int optcopies; int optbeg, optend; int pagenum; /* Page size tables. * (See Figures 2-2 and 2-3 in the LaserJet 2P Technical Reference Manual.) * * Let Legal Exec A4 COM10 Mon C5 DL */ int psize[MAXSIZE] = { 2, 3, 1, 26, 81, 80, 91, 90 }; int xsize[MAXSIZE] = { 2550, 2550, 2175, 2480, 1237, 1162, 1913, 1299 }; int ysize[MAXSIZE] = { 3300, 4200, 3150, 3507, 2850, 2250, 2704, 2598 }; int ppoff[MAXSIZE] = { 75, 75, 75, 71, 75, 75, 71, 71 }; int ploff[MAXSIZE] = { 60, 60, 60, 59, 60, 60, 59, 59 }; char *showsize[MAXSIZE] = {"letter", "legal", "executive", "A4", "COM-10", "monarch", "C5", "DL" }; char *showland[2] = {"portrait", "landscape" }; int compsize; char *compbuf; /* Arguments */ char *argto = "par:"; int argfilec, argmemc; char *argfilev[5], *argmemv[5]; char *argkey[] = { "TO", "MEM", NULL }; /* Startup code */ extern void main(int argc, char **argv); void _main(char *line) { char *argv[32]; int argc; /* Parse the arguments to break words and strip quotes. N.B. the * main program can determine that the arument was quoted by inspecting * the preceeding character */ argc = 0; if (line == NULL) goto endline; for (;;) { while (*line == ' ' || *line == '\t' || *line == '\n') line++; if (*line == 0) break; if (argc == 32) { argc = 0; goto endline; } if (*line == '"') { argv[argc] = ++line; while (*line != '"') { if (*line == 0) { argc = 0; goto endline; } line++; } } else { argv[argc] = line; while (*line != ' ' && *line != '\t' && *line != '\n') { if (*line == 0) { argc++; goto endline; } line++; } } *line++ = 0; argc++; } endline: /* Set up the standard input/output files */ errfh = Open("*", MODE_OLDFILE); if (errfh == NULL) { retcode = 20; goto tidyexit; } _ufbs[2].ufbfh = (long) errfh; _ufbs[2].ufbflg |= UFB_WA|O_RAW|UFB_NC; stderr->_file = 2; stderr->_flag = _IOWRT; setbuf(stderr, NULL); /* Call the main program */ main(argc, argv); /* Tidy up and exit */ tidyexit: if (errfh) Close(errfh); XCEXIT(retcode); } /* Main program */ void main(int argc, char **argv) { char *s, *t; int *ip, i, m, n, ch; /* Open the libraries */ PSbase = OpenLibrary("post.library", POSTVERNO); if (PSbase == NULL) { fprintf(stderr, "postlj: can't open post.library\n"); goto errorexit; } /* Parse the arguments and keywords. See the usage string below */ argc--; argv++; if (argc == 0 || (argc == 1 && strcmp(*argv, "?") == 0)) goto usage; while (argc--) { s = *argv++; i = -1; if (s[-1] != '"') if (*s == '-') { s++; while (t = s, ch = *s++) { switch (ch) { case 'S': case 's': m = MAXSIZE; ip = &optsize; break; case 'L': case 'l': m = 2; ip = &optland; break; case 'B': case 'b': m = 10000; ip = &optbeg; break; case 'E': case 'e': m = 10000; ip = &optend; break; case 'N': case 'n': m = 100; ip = &optcopies; break; case 'C': case 'c': m = 2; ip = &optcomp; break; default: fprintf(stderr, "postlj: unknown option \"%c\"\n", ch); goto badusage; } if (!strtoint(&s, &i)) goto badvalue; if ((unsigned) i >= m) { fprintf(stderr, "postlj: option value out of range " "(0-%d) \"%.*s\"\n", m - 1, s - t, t); goto errorexit; } *ip = i; } continue; } else for (;;) { i++; if (argkey[i] == NULL) { i = -1; break; } if (stricmp(s, argkey[i]) == 0) break; } switch (i) { case 0: /* TO */ if (argc == 0) goto badargs; argc--; argto = *argv++; break; case 1: /* MEM */ if (argc == 0) goto badargs; argc--; if (argmemc == 5) goto badargs; argmemv[argmemc++] = *argv++; break; default: if (argfilec == 5) goto badargs; argfilev[argfilec++] = s; } } /* Parse the "MEM fhlv.." options */ for (i = 0; i < argmemc; i++) { s = argmemv[i]; for (;;) { ch = *s++; if (ch == 0) break; ch = tolower(ch); switch (ch) { case 'f': ip = &parm.memflen; break; case 'h': ip = &parm.memhlen; break; case 'l': ip = &parm.memllen; break; case 'v': ip = &parm.memvlen; break; default: goto badvalue; } if (!strtoint(&s, ip)) goto badvalue; } } /* Determine the page size */ if (optland) { n = xsize[optsize]; m = ysize[optsize]; } else { m = xsize[optsize]; n = ysize[optsize]; } parm.page.depth = 1; parm.page.xoff = parm.page.yoff = 0; parm.page.xsize = m; parm.page.ysize = n; parm.page.xbytes = (parm.page.xsize + 7) >> 3; parm.page.len = parm.page.xbytes * parm.page.ysize; parm.page.ybase = 0; parm.page.yheight = parm.page.ysize; parm.page.xden = parm.page.yden = 300; parm.page.ydir = -1; /* Allocate the page buffer */ for (i = 0; i < parm.page.depth; i++) { if ((parm.page.buf[i] = AllocMem(parm.page.len, MEMF_PUBLIC|MEMF_CLEAR)) == NULL) { fprintf(stderr, "postlj: can't get page buffer\n"); goto errorexit; } } /* Allocate the print compression buffer */ compsize = parm.page.xbytes + parm.page.xbytes / 128 + 2; compbuf = AllocMem(compsize, MEMF_PUBLIC); if (compbuf == NULL) { fprintf(stderr, "postlj: can't get memory\n"); goto errorexit; } /* Open a file to the par: handler and initialise the printer */ parfp = fopen(argto, "w"); if (parfp == NULL) { fprintf(stderr, "postlj: can't open %s\n", argto); goto errorexit; } prtsetup(); if (ferror(parfp)) { fprintf(stderr, "postlj: error writing printer file\n"); goto errorexit; } /* Initialise for interpretation */ insertbreak(); SetExcept(~0, SIGBREAKF_CTRL_C); breakset = 1; insertftrap(); ftrapset = 1; parm.copyfunc = (APTR) copypage; parm.infh = Input(); parm.outfh = Output(); parm.errfh = errfh; arec = PScreateact(&parm); if (arec == 0) { fprintf(stderr, "postlj: can't get memory\n"); goto errorexit; } if ((unsigned) arec <= errmax) { arec = 0; retcode = 10; goto tidyexit; } /* Interpret the argument files */ fprintf(stderr, "postlj: running (%s, %s)\n", showsize[optsize], showland[optland]); pagenum = 0; for (i = 0; i < argfilec; i++) if (PSintstring(arec, argfilev[i], -1, PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE) != 0) { retcode = 10; goto tidyexit; } if (ferror(parfp)) { fprintf(stderr, "postlj: error writing printer file\n"); goto errorexit; } fprintf(stderr, "postlj: finished\n"); goto tidyexit; /* Argument errors and usage query */ badargs: fprintf(stderr, "postlj: arguments bad, or value missing\n"); goto badusage; badvalue: fprintf(stderr, "postlj: argument bad value\n"); badusage: retcode = 20; usage: fprintf(stderr, "postlj: usage:\n" " postlj -s.l.b.e.n.c. [files...] [TO tofile] [MEM fhlv..]\n"); goto tidyexit; /* Tidy up and exit */ errorexit: retcode = 20; tidyexit: if (breakset) { SetExcept(0, SIGBREAKF_CTRL_C); deletebreak(); breakset = 0; } if (ftrapset) { deleteftrap(); ftrapset = 0; } if (arec) PSdeleteact(arec); if (parfp) { prtreset(); fclose(parfp); } if (compbuf) FreeMem(compbuf, compsize); for (i = 0; i < parm.page.depth; i++) if (parm.page.buf[i]) { FreeMem(parm.page.buf[i], parm.page.len); parm.page.buf[i] = NULL; } if (PSbase) CloseLibrary(PSbase); } /* String to integer conversion; digits only, with error check */ int strtoint(char **sp, int *ip) { char *s = *sp; int i = 0; int ch; for (;;) { ch = *s; if (ch < '0' || ch > '9') break; i = i * 10 + (ch - '0'); s++; } if (s == *sp) return 0; else { *sp = s; *ip = i; return 1; } } /* Signal an interrupt */ void __saveds sigint() { PSsignalint(arec, 1); } /* Signal a floating point error */ void __saveds sigfpe() { PSsignalfpe(arec); } /* Copy the page to the output */ void __saveds __asm copypage(register __d0 int num) { pagenum++; if ((optbeg == 0 || pagenum >= optbeg) && (optend == 0 || pagenum <= optend)) { prtdump(optcopies == 0 ? num : optcopies); if (ferror(parfp)) PSerror(arec, errioerror); } } /* Printer setup */ void prtsetup(void) { /* Printer reset, Page size, Orientation, Perf skip off, Top Mgn 0 */ fprintf(parfp, "\33E\33&l%da%do0l0E", psize[optsize], optland); /* Long edge offset, Short edge offset */ if (optland) fprintf(parfp, "\33&l%dz%dU", -(150 - ploff[optsize] * 720) / 300, 0); else fprintf(parfp, "\33&l%du%dZ", (150 - ppoff[optsize] * 720) / 300, 0); } /* Printer reset */ void prtreset(void) { fprintf(parfp, "\33E"); } /* Printer dump */ void prtdump(int num) { char *buf; int ysize; /* Set the number of copies */ if (num == 0 || num > 99) num = 1; fprintf(parfp, "\33&l%dX", num); /* Set cursor to (0,0), 300 dpi, aligned logical page, start graphics */ fprintf(parfp, "\33*p0x0Y\33*t300R\33*r0f0A"); /* Loop for the rows */ buf = parm.page.buf[0]; ysize = parm.page.ysize; while (ysize--) { prtdumpline(buf, parm.page.xbytes); buf += parm.page.xbytes; } /* End graphics, form feed, reset number of copies */ fprintf(parfp, "\33*rB\14\33&l1X"); } /* Dump a line of pixels */ void prtdumpline(char *buf, int len) { char *ptr; int b, c, l; /* Strip trailing zeros */ while (len && buf[len - 1] == 0) len--; /* Compression */ if (optcomp) { ptr = compbuf; l = 0; while (len--) { b = *buf++; /* Pick up a byte */ c = 1; while (len && *buf == b && c < 128) { c++; buf++; len--; /* See if it begins a run */ } if (c == 2 && /* If a two byte run */ l > 0 && /* and preceeded by literals */ l <= 125 && /* and not more than 125 of them */ (len <= 2 || /* and no more than 2 bytes left */ *buf != *(buf + 1))) /* or not followed by a run */ { c = 1; /* Then make it a literal */ buf--; len++; } if (c == 1) /* If not a run */ { l++; /* Then it must be a literal */ c = 0; } if (l > 0 && /* If we have some literals */ (c > 1 || /* and beginning a run */ l == 127 || /* or reached 127 */ len == 0)) /* or no more bytes left */ { *ptr++ = l - 1; /* Then write out the literals */ memcpy(ptr, buf - c - l, l); ptr += l; l = 0; } if (c > 1) /* If we have a run */ { *ptr++ = 1 - c; /* Then write it */ *ptr++ = b; } } len = ptr - compbuf; fprintf(parfp, "\33*b2m%dW", len); buf = compbuf; } /* No compression */ else fprintf(parfp, "\33*b%dW", len); fwrite(buf, 1, len, parfp); } /* Dummy stub routine */ void stub(void) { return; } /* Dummy check abort routine */ void chkabort(void) { return; } /* End of file "postlj.c" */