home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / c / post17s.lha / postlj.c < prev    next >
C/C++ Source or Header  |  1992-03-09  |  21KB  |  787 lines

  1. /* LaserJet print driver for Post.  File "postlj.c"
  2.  * (C) Adrian Aylward 1990, 1992
  3.  *
  4.  * You may freely copy, use, and modify this file.
  5.  *
  6.  * This program prints PostScript files to a LaserJet.  It sends the output
  7.  * to the PAR: handler.  Page size and orientation are read from the command
  8.  * line.  There are no printer status checks; if the output hangs check your
  9.  * printer is ready.  It is totally Amiga specific.
  10.  *
  11.  * The program was tested using Lattice C V5.05.  It has various Lattice
  12.  * dependencies.
  13.  *
  14.  * V1.6 First full source release
  15.  * V1.7 New options for custom page size and DeskJet etc.
  16.  */
  17.  
  18. # include <dos.h>
  19. # include <devices/printer.h>
  20. # include <devices/prtbase.h>
  21. # include <exec/exec.h>
  22. # include <exec/execbase.h>
  23. # include <exec/tasks.h>
  24. # include <graphics/gfx.h>
  25. # include <graphics/rastport.h>
  26. # include <proto/dos.h>
  27. # include <proto/exec.h>
  28. # include <string.h>
  29. # include <stdio.h>
  30. # include <fcntl.h>
  31. # include <ios1.h>
  32.  
  33. # include "postlib.h"
  34.  
  35. # undef  POSTVERNO
  36. # define POSTVERNO 15  /* We need post.library version 1.5+ */
  37.  
  38. /* Assembler routines */
  39.  
  40. extern void insertbreak(void);
  41. extern void deletebreak(void);
  42. extern void insertftrap(void);
  43. extern void deleteftrap(void);
  44.  
  45. /* Routines defined and referenced only within this module */
  46.  
  47. extern int  strtoint(char **sp, int *ip);
  48. extern void __saveds __asm copypage(register __d0 int num);
  49. extern void prtsetup(void);
  50. extern void prtreset(void);
  51. extern void prtdump(int copies);
  52. extern void prtdumpline(char *buf, int len);
  53.  
  54. /* Lattice startup */
  55.  
  56. extern struct UFB _ufbs[];
  57.  
  58. /* External data (initialised to zero) */
  59.  
  60. int retcode;
  61.  
  62. int arec;
  63.  
  64. BPTR errfh;
  65. FILE *parfp;
  66.  
  67. struct library *PSbase;
  68. struct PSparm parm;
  69.  
  70. int breakset, ftrapset;
  71.  
  72. /* Options */
  73.  
  74. # define DEFSIZE 3 /* A4 page size */
  75. # define DEFLAND 0 /* Portrait orientation */
  76. # define DEFLJ   2 /* LaserJet IIP,III,IIIp etc. */
  77.  
  78. # define MAXSIZE 8
  79. # define MAXLJ   3
  80.  
  81. int optsize = DEFSIZE;
  82. int optland = DEFLAND;
  83. int optlj   = DEFLJ;
  84. int optgc;
  85. int optcopies;
  86. int optbeg, optend;
  87. int optxsize, optysize;
  88. int optlmarg, optrmarg, optumarg, optdmarg;
  89. int opthoff, optvoff;
  90.  
  91. int pagenum;
  92. int hoffset, voffset, vmarg;
  93.  
  94. /* Page size tables.
  95.  * (See Figures 2-2 and 2-3 in the LaserJet 2P Technical Reference Manual.)
  96.  *
  97.  *                     Let   Legal Exec  A4    COM10 Mon   C5    DL
  98.  */
  99.  
  100. int psize[MAXSIZE] = {    2,    3,    1,   26,   81,   80,   91,   90 };
  101.  
  102. int xsize[MAXSIZE] = { 2550, 2550, 2175, 2480, 1237, 1162, 1913, 1299 };
  103. int ysize[MAXSIZE] = { 3300, 4200, 3150, 3507, 2850, 2250, 2704, 2598 };
  104. int ppoff[MAXSIZE] = {   75,   75,   75,   71,   75,   75,   71,   71 };
  105. int ploff[MAXSIZE] = {   60,   60,   60,   59,   60,   60,   59,   59 };
  106.  
  107. char *showlj[MAXLJ] = {"DeskJet", "LaserJet II", "LaserJet IIP/III" };
  108. char *showsize[MAXSIZE] = {"letter", "legal", "executive", "A4",
  109.                            "COM-10", "monarch", "C5", "DL" };
  110. char *showland[2] = {"vertical", "horizontal" };
  111.  
  112. int compsize;
  113. char *compbuf;
  114.  
  115. /* Arguments */
  116.  
  117. char *argto = "par:";
  118. int argfilec, argmemc;
  119. char *argfilev[5], *argmemv[5];
  120. char *argkey[] =
  121. {   "TO", "MEM", NULL };
  122.  
  123. /* Startup code */
  124.  
  125. extern void main(int argc, char **argv);
  126.  
  127. void _main(char *line)
  128. {   char *argv[32];
  129.     int argc;
  130.  
  131.     /* Parse the arguments to break words and strip quotes.  N.B. the
  132.      * main program can determine that the arument was quoted by inspecting
  133.      * the preceeding character */
  134.  
  135.     argc = 0;
  136.     if (line == NULL) goto endline;
  137.     for (;;)
  138.     {   while (*line == ' ' || *line == '\t' || *line == '\n') line++;
  139.         if (*line == 0) break;
  140.         if (argc == 32)
  141.         {   argc = 0;
  142.             goto endline;
  143.         }
  144.         if (*line == '"')
  145.         {   argv[argc] = ++line;
  146.             while (*line != '"')
  147.             {   if (*line == 0)
  148.                 {   argc = 0;
  149.                     goto endline;
  150.                 }
  151.                 line++;
  152.             }
  153.         }
  154.         else
  155.         {   argv[argc] = line;
  156.             while (*line != ' ' && *line != '\t' && *line != '\n')
  157.             {   if (*line == 0)
  158.                 {   argc++;
  159.                     goto endline;
  160.                 }
  161.                 line++;
  162.             }
  163.         }
  164.         *line++ = 0;
  165.         argc++;
  166.     }
  167. endline:
  168.  
  169.     /* Set up the standard input/output files */
  170.  
  171.     errfh = Open("*", MODE_OLDFILE);
  172.     if (errfh == NULL)
  173.     {   retcode = 20;
  174.         goto tidyexit;
  175.     }
  176.     _ufbs[2].ufbfh = (long) errfh;
  177.     _ufbs[2].ufbflg |= UFB_WA|O_RAW|UFB_NC;
  178.     stderr->_file = 2;
  179.     stderr->_flag = _IOWRT;
  180.  
  181.     /* Call the main program  */
  182.  
  183.     main(argc, argv);
  184.  
  185.     /* Tidy up and exit */
  186.  
  187. tidyexit:
  188.     if (errfh) Close(errfh);
  189.  
  190.     XCEXIT(retcode);
  191. }
  192.  
  193. /* Main program */
  194.  
  195. void main(int argc, char **argv)
  196. {   char *s, *t;
  197.     int *ip, i, m, ch;
  198.     int x, y, l, r, u, d, h, v;
  199.  
  200.     /* Open the libraries */
  201.  
  202.     PSbase = OpenLibrary("post.library", POSTVERNO);
  203.     if (PSbase == NULL)
  204.     {   fprintf(stderr, "postlj: can't open post.library\n");
  205.         goto errorexit;
  206.     }
  207.  
  208.     /* Parse the arguments and keywords.  See the usage string below */
  209.  
  210.     argc--;
  211.     argv++;
  212.     if (argc == 0 || (argc == 1 && strcmp(*argv, "?") == 0)) goto query;
  213.  
  214.     optxsize = optysize = -1;
  215.     optlmarg = optrmarg = optumarg = optdmarg = -1;
  216.     opthoff = optvoff = -1;
  217.     optgc = -1;
  218.  
  219.     while (argc)
  220.     {   s = *argv;
  221.         if (*s != '-') break;
  222.         argv++;
  223.         argc--;
  224.         if (strcmp(s, "--") == 0) break;
  225.         s++;
  226.         while (t = s, ch = *s++)
  227.         {   switch (ch)
  228.             {   case 'S': case 's':
  229.                    m = MAXSIZE;
  230.                    ip = &optsize;
  231.                    break;
  232.  
  233.                 case 'A': case 'a':
  234.                    m = 2;
  235.                    ip = &optland;
  236.                    break;
  237.  
  238.                 case 'J': case 'j':
  239.                    m = MAXLJ;
  240.                    ip = &optlj;
  241.                    break;
  242.  
  243.                 case 'G': case 'g':
  244.                    m = 2;
  245.                    ip = &optgc;
  246.                    break;
  247.  
  248.                 case 'B': case 'b':
  249.                    m = 10000;
  250.                    ip = &optbeg;
  251.                    break;
  252.  
  253.                 case 'E': case 'e':
  254.                    m = 10000;
  255.                    ip = &optend;
  256.                    break;
  257.  
  258.                 case 'C': case 'c':
  259.                    m = 100;
  260.                    ip = &optcopies;
  261.                    break;
  262.  
  263.                 case 'X': case 'x':
  264.                    m = 30000;
  265.                    ip = &optxsize;
  266.                    break;
  267.  
  268.                 case 'Y': case 'y':
  269.                    m = 30000;
  270.                    ip = &optysize;
  271.                    break;
  272.  
  273.                 case 'L': case 'l':
  274.                    m = 30000;
  275.                    ip = &optlmarg;
  276.                    break;
  277.  
  278.                 case 'R': case 'r':
  279.                    m = 30000;
  280.                    ip = &optrmarg;
  281.                    break;
  282.  
  283.                 case 'U': case 'u':
  284.                    m = 30000;
  285.                    ip = &optumarg;
  286.                    break;
  287.  
  288.                 case 'D': case 'd':
  289.                    m = 30000;
  290.                    ip = &optdmarg;
  291.                    break;
  292.  
  293.                 case 'H': case 'h':
  294.                    m = 30000;
  295.                    ip = &opthoff;
  296.                    break;
  297.  
  298.                 case 'V': case 'v':
  299.                    m = 30000;
  300.                    ip = &optvoff;
  301.                    break;
  302.  
  303.                 default:
  304.                    fprintf(stderr,
  305.                            "postlj: unknown option \"%c\"\n", ch);
  306.                    goto badusage;
  307.             }
  308.             if (!strtoint(&s, &i)) goto badvalue;
  309.             if ((unsigned) i >= m)
  310.             {   fprintf(stderr,
  311.                         "postlj: option value out of range "
  312.                         "(0-%d) \"%.*s\"\n", m - 1, s - t, t);
  313.                 goto errorexit;
  314.             }
  315.             *ip = i;
  316.         }
  317.     }
  318.  
  319.     while (argc--)
  320.     {   s = *argv++;
  321.         i = -1;
  322.         if (s[-1] != '"')
  323.             for (;;)
  324.             {   i++;
  325.                 if (argkey[i] == NULL)
  326.                 {   i = -1;
  327.                     break;
  328.                 }
  329.                 if (stricmp(s, argkey[i]) == 0) break;
  330.             }
  331.         switch (i)
  332.         {   case  0:    /* TO */
  333.                 if (argc == 0) goto badargs;
  334.                 argc--;
  335.                 argto = *argv++;
  336.                 break;
  337.  
  338.             case  1:    /* MEM */
  339.                 if (argc == 0) goto badargs;
  340.                 argc--;
  341.                 if (argmemc == 5) goto badargs;
  342.                 argmemv[argmemc++] = *argv++;
  343.                 break;
  344.  
  345.             default:
  346.                 if (argfilec == 5) goto badargs;
  347.                 argfilev[argfilec++] = s;
  348.         }
  349.     }
  350.  
  351.     /* Parse the "MEM fhlv.." options */
  352.  
  353.     for (i = 0; i < argmemc; i++)
  354.     {   s = argmemv[i];
  355.         for (;;)
  356.         {   ch = *s++;
  357.             if (ch == 0) break;
  358.             ch = tolower(ch);
  359.             switch (ch)
  360.             {   case 'f':
  361.                     ip = &parm.memflen;
  362.                     break;
  363.  
  364.                 case 'h':
  365.                     ip = &parm.memhlen;
  366.                     break;
  367.  
  368.                 case 'l':
  369.                     ip = &parm.memllen;
  370.                     break;
  371.  
  372.                 case 'v':
  373.                     ip = &parm.memvlen;
  374.                     break;
  375.  
  376.                 default:
  377.                     goto badvalue;
  378.             }
  379.             if (!strtoint(&s, ip)) goto badvalue;
  380.         }
  381.     }
  382.  
  383.     /* Determine the page size */
  384.  
  385.  
  386.     x = xsize[optsize];
  387.     y = ysize[optsize];
  388.     h = ppoff[optsize];
  389.     v = ploff[optsize];
  390.     if (optland)
  391.     {   i = x;
  392.         x = y;
  393.         y = i;
  394.         i = h;
  395.         h = v;
  396.         v = i;
  397.     }
  398.     if      (optlj == 0) /* DeskJet..., margins are 150 pixels */
  399.     {   l = r = 150;
  400.         u = d = 150;
  401.     }
  402.     else if (optlj == 1) /* LJ II..., printable area is logical page */
  403.     {   l = r = h;
  404.         u = d = v;
  405.     }
  406.     else                 /* LJ IIP/III..., margins are 50 pixels */
  407.     {   l = r = 50;
  408.         u = d = 50;
  409.         v = u;
  410.     }
  411.     if (optxsize >= 0) x = optxsize;
  412.     if (optysize >= 0) y = optysize;
  413.     if (optlmarg >= 0) l = optlmarg;
  414.     if (optrmarg >= 0) r = optrmarg;
  415.     if (optumarg >= 0) u = optumarg;
  416.     if (optdmarg >= 0) d = optdmarg;
  417.     if (opthoff  >= 0) h = opthoff;
  418.     if (optvoff  >= 0) v = optvoff;
  419.     if (x <= l + r || y <= u + d)
  420.     {   fprintf(stderr, "postlj: page size smaller than margins\n");
  421.         goto errorexit;
  422.     }
  423.     hoffset = ((h - l) * 720) / 300;
  424.     voffset = ((v - u) * 720) / 300;
  425.     vmarg = u;
  426.     if (optlj == 0)      /* DeskJet, logical page is at top margin */
  427.         vmarg = 0;
  428.  
  429.     if (optgc == -1)      /* Default graphics compression */
  430.         if (optlj == 1)
  431.             optgc = 0;   /* Off for LaserJet II */
  432.         else
  433.             optgc = 1;   /* On  for LaserJet IIP/III and DeskJet */
  434.  
  435.     parm.page.depth = 1;
  436.     parm.page.xoff = l;
  437.     parm.page.yoff = d;
  438.     parm.page.xsize = x - l - r;
  439.     parm.page.ysize = y - u - d;
  440.     parm.page.xbytes = (parm.page.xsize + 7) >> 3;
  441.     parm.page.len = parm.page.xbytes * parm.page.ysize;
  442.     parm.page.ybase = 0;
  443.     parm.page.yheight = parm.page.ysize;
  444.     parm.page.xden = parm.page.yden = 300;
  445.     parm.page.ydir = -1;
  446.  
  447.     /* Allocate the page buffer */
  448.  
  449.     for (i = 0; i < parm.page.depth; i++)
  450.     {   if ((parm.page.buf[i] =
  451.                 AllocMem(parm.page.len, MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
  452.         {   fprintf(stderr, "postlj: can't get page buffer\n");
  453.             goto errorexit;
  454.         }
  455.     }
  456.  
  457.     /* Allocate the print compression buffer */
  458.  
  459.     compsize = parm.page.xbytes + parm.page.xbytes / 128 + 2;
  460.     compbuf = AllocMem(compsize, MEMF_PUBLIC);
  461.     if (compbuf == NULL)
  462.     {   fprintf(stderr, "postlj: can't get memory\n");
  463.         goto errorexit;
  464.     }
  465.  
  466.     /* Open a file to the par: handler and initialise the printer */
  467.  
  468.     parfp = fopen(argto, "w");
  469.     if (parfp == NULL)
  470.     {   fprintf(stderr, "postlj: can't open %s\n", argto);
  471.         goto errorexit;
  472.     }
  473.     prtsetup();
  474.     if (ferror(parfp))
  475.     {   fprintf(stderr, "postlj: error writing printer file\n");
  476.         goto errorexit;
  477.     }
  478.  
  479.     /* Initialise for interpretation */
  480.  
  481.     insertbreak();
  482.     SetExcept(~0, SIGBREAKF_CTRL_C);
  483.     breakset = 1;
  484.     insertftrap();
  485.     ftrapset = 1;
  486.  
  487.     parm.copyfunc = (APTR) copypage;
  488.  
  489.     parm.infh = Input();
  490.     parm.outfh = Output();
  491.     parm.errfh = errfh;
  492.  
  493.     arec = PScreateact(&parm);
  494.     if (arec == 0)
  495.     {   fprintf(stderr, "postlj: can't get memory\n");
  496.         goto errorexit;
  497.     }
  498.     if ((unsigned) arec <= errmax)
  499.     {   arec = 0;
  500.         retcode = 10;
  501.         goto tidyexit;
  502.     }
  503.  
  504.     /* Interpret the argument files */
  505.  
  506.     fprintf(stderr, "postlj: running on %s (%s, %s, (%d:%d:%d * %d:%d:%d))\n",
  507.             showlj[optlj], showsize[optsize], showland[optland],
  508.             l, x-l-r, r, u, y-u-d, d);
  509.  
  510.     pagenum = 0;
  511.     for (i = 0; i < argfilec; i++)
  512.         if (PSintstring(arec, argfilev[i],
  513.                         -1, PSFLAGFILE|PSFLAGCLEAR|PSFLAGERASE) != 0)
  514.         {   retcode = 10;
  515.             goto tidyexit;
  516.         }
  517.  
  518.     if (ferror(parfp))
  519.     {   fprintf(stderr, "postlj: error writing printer file\n");
  520.         goto errorexit;
  521.     }
  522.     fprintf(stderr, "postlj: finished\n");
  523.     goto tidyexit;
  524.  
  525.     /* Argument errors and usage query */
  526.  
  527. query:
  528.     fprintf(stderr, "LaserJet or DeskJet driver for Post. PostLJ version "
  529.                         "1.7\n");
  530.     fprintf(stderr, "Drives the printer directly for control of page size and "
  531.                         "better performance\n");
  532.     fprintf(stderr, "\n");
  533.     fprintf(stderr, "  Usage:\n");
  534.     fprintf(stderr, "\n");
  535.     fprintf(stderr, "    postlj -options [files...] [TO tofile] [MEM fhlv..]"
  536.                         "\n");
  537.     fprintf(stderr, "\n");
  538.     fprintf(stderr, "      -sn     Page size (0 = Letter, 1 = Legal, 2 = "
  539.                         "Executive, 3 = A4,\n");
  540.     fprintf(stderr, "                         4 = COM10, 5 = Monarch, 6 = "
  541.                         "C5, 7 = DL)\n");
  542.     fprintf(stderr, "      -an     Aspect (0 = vertical, 1 = horizontal)\n");
  543.     fprintf(stderr, "      -jn     LaserJet model (0 = DJ, 1 = LJII, 2 = "
  544.                         "LJIIP/III)\n");
  545.     fprintf(stderr, "      -gn     Graphics compression (0 = off, 1 = on)\n");
  546.     fprintf(stderr, "      -bnnnn  Page number to begin printing at\n");
  547.     fprintf(stderr, "      -ennnn  Page number to end printing after\n");
  548.     fprintf(stderr, "      -cnn    Number of copies\n");
  549.     fprintf(stderr, "      -xnnnnn Paper x size\n");
  550.     fprintf(stderr, "      -ynnnnn Paper y size\n");
  551.     fprintf(stderr, "      -lnnnnn Left  margin\n");
  552.     fprintf(stderr, "      -rnnnnn Right margin\n");
  553.     fprintf(stderr, "      -unnnnn Upper margin\n");
  554.     fprintf(stderr, "      -dnnnnn Lower margin\n");
  555.     fprintf(stderr, "      -hnnnnn Horizontal offset registration\n");
  556.     fprintf(stderr, "      -vnnnnn Vertical   offset registration\n");
  557.     fprintf(stderr, "\n");
  558.     fprintf(stderr, "  Defaults are A4, portrait, LJIIP/III\n");
  559.     fprintf(stderr, "\n");
  560.     fprintf(stderr, "  For example:\n");
  561.     fprintf(stderr, "\n");
  562.     fprintf(stderr, "    postlj -a1 -j1 psfonts:init.ps myfile.ps\n");
  563.     fprintf(stderr, "\n");
  564.     fprintf(stderr, "  Prints on A4 paper, portrait orientation, using a "
  565.                         "LaserJet II\n");
  566.     goto tidyexit;
  567.  
  568. badargs:
  569.     fprintf(stderr, "postlj: arguments bad, or value missing\n");
  570.     goto badusage;
  571.  
  572. badvalue:
  573.     fprintf(stderr, "postlj: argument bad value\n");
  574.  
  575. badusage:
  576.     retcode = 20;
  577.     fprintf(stderr, "postlj: usage:\n"
  578.     "    postlj -sajgbecxylruhv [files...] [TO tofile] [MEM fhlv..]\n");
  579.     goto tidyexit;
  580.  
  581.     /* Tidy up and exit */
  582.  
  583. errorexit:
  584.     retcode = 20;
  585.  
  586. tidyexit:
  587.     if (breakset)
  588.     {   SetExcept(0, SIGBREAKF_CTRL_C);
  589.         deletebreak();
  590.         breakset = 0;
  591.     }
  592.     if (ftrapset)
  593.     {   deleteftrap();
  594.         ftrapset = 0;
  595.     }
  596.  
  597.     if (arec) PSdeleteact(arec);
  598.  
  599.     if (parfp)
  600.     {   prtreset();
  601.         fclose(parfp);
  602.     }
  603.  
  604.     if (compbuf) FreeMem(compbuf, compsize);
  605.  
  606.     for (i = 0; i < parm.page.depth; i++)
  607.         if (parm.page.buf[i])
  608.         {   FreeMem(parm.page.buf[i], parm.page.len);
  609.             parm.page.buf[i] = NULL;
  610.         }
  611.  
  612.     if (PSbase) CloseLibrary(PSbase);
  613. }
  614.  
  615. /* String to integer conversion; digits only, with error check */
  616.  
  617. int strtoint(char **sp, int *ip)
  618. {   char *s = *sp;
  619.     int i = 0;
  620.     int ch;
  621.     for (;;)
  622.     {   ch = *s;
  623.         if (ch < '0' || ch > '9') break;
  624.         i = i * 10 + (ch - '0');
  625.         s++;
  626.     }
  627.     if (s == *sp)
  628.         return 0;
  629.     else
  630.     {   *sp = s;
  631.         *ip = i;
  632.         return 1;
  633.     }
  634. }
  635.  
  636. /* Signal an interrupt */
  637.  
  638. void __saveds sigint()
  639. {   PSsignalint(arec, 1);
  640. }
  641.  
  642. /* Signal a floating point error */
  643.  
  644. void __saveds sigfpe()
  645. {   PSsignalfpe(arec);
  646. }
  647.  
  648. /* Copy the page to the output */
  649.  
  650. void __saveds __asm copypage(register __d0 int num)
  651. {   pagenum++;
  652.     if ((optbeg == 0 || pagenum >= optbeg) &&
  653.         (optend == 0 || pagenum <= optend))
  654.     {   prtdump(optcopies == 0 ? num : optcopies);
  655.         if (ferror(parfp)) PSerror(arec, errioerror);
  656.     }
  657. }
  658.  
  659. /* Printer setup */
  660.  
  661. void prtsetup(void)
  662. {
  663.     /* Printer reset, Page size, Orientation, Perf skip off, Top Mgn 0 */
  664.  
  665.     fprintf(parfp, "\33E\33&l%da%do0l0E", psize[optsize], optland);
  666.  
  667.     /* Long edge offset, Short edge offset */
  668.  
  669.     if (optland)
  670.         fprintf(parfp, "\33&l%du%dZ",  voffset, hoffset);
  671.     else
  672.         fprintf(parfp, "\33&l%du%dZ", -hoffset, voffset);
  673. }
  674.  
  675. /* Printer reset */
  676.  
  677. void prtreset(void)
  678. {   fprintf(parfp, "\33E");
  679. }
  680.  
  681. /* Printer dump */
  682.  
  683. void prtdump(int num)
  684. {   char *buf;
  685.     int ysize;
  686.  
  687.     /* Set the number of copies */
  688.  
  689.     if (num == 0 || num > 99) num = 1;
  690.     fprintf(parfp, "\33&l%dX", num);
  691.  
  692.     /* Set cursor to (0,vmarg), 300 dpi, aligned logical page, start graphics */
  693.  
  694.     fprintf(parfp, "\33*p0x%dY\33*t300R\33*r0f0A", vmarg);
  695.  
  696.     /* Loop for the rows */
  697.  
  698.     buf = parm.page.buf[0];
  699.     ysize = parm.page.ysize;
  700.  
  701.     while (ysize--)
  702.     {   prtdumpline(buf, parm.page.xbytes);
  703.         buf += parm.page.xbytes;
  704.     }
  705.  
  706.     /* End graphics, form feed, reset number of copies */
  707.  
  708.     fprintf(parfp, "\33*rB\14\33&l1X");
  709. }
  710.  
  711. /* Dump a line of pixels */
  712.  
  713. void prtdumpline(char *buf, int len)
  714. {   char *ptr;
  715.     int b, c, l;
  716.  
  717.     /* Strip trailing zeros */
  718.  
  719.     while (len && buf[len - 1] == 0) len--;
  720.  
  721.     /* Compression */
  722.  
  723.     if (optgc)
  724.     {   ptr = compbuf;
  725.         l = 0;
  726.         while (len--)
  727.         {   b = *buf++;                  /* Pick up a byte */
  728.             c = 1;
  729.             while (len && *buf == b && c < 128)
  730.             {   c++;
  731.                 buf++;
  732.                 len--;                   /* See if it begins a run */
  733.             }
  734.             if (c == 2 &&                /* If a two byte run */
  735.                 l > 0 &&                 /*  and preceeded by literals */
  736.                 l <= 125 &&              /*  and not more than 125 of them */
  737.                 (len <= 2 ||             /*  and no more than 2 bytes left */
  738.                  *buf != *(buf + 1)))    /*      or not followed by a run */
  739.             {   c = 1;                   /* Then make it a literal */
  740.                 buf--;
  741.                 len++;
  742.             }
  743.             if (c == 1)                  /* If not a run */
  744.             {   l++;                     /* Then it must be a literal */
  745.                 c = 0;
  746.             }
  747.             if (l > 0 &&                 /* If we have some literals */
  748.                 (c > 1 ||                /*  and beginning a run */
  749.                  l == 127 ||             /*  or reached 127 */
  750.                  len == 0))              /*  or no more bytes left */
  751.             {   *ptr++ = l - 1;          /* Then write out the literals */
  752.                 memcpy(ptr, buf - c - l, l);
  753.                 ptr += l;
  754.                 l = 0;
  755.             }
  756.             if (c > 1)                   /* If we have a run */
  757.             {   *ptr++ = 1 - c;          /* Then write it */
  758.                 *ptr++ = b;
  759.             }
  760.         }
  761.         len = ptr - compbuf;
  762.         fprintf(parfp, "\33*b2m%dW", len);
  763.         buf = compbuf;
  764.     }
  765.  
  766.     /* No compression */
  767.  
  768.     else
  769.         fprintf(parfp, "\33*b%dW", len);
  770.  
  771.     fwrite(buf, 1, len, parfp);
  772. }
  773.  
  774. /* Dummy stub routine */
  775.  
  776. void stub(void)
  777. {   return;
  778. }
  779.  
  780. /* Dummy check abort routine */
  781.  
  782. void chkabort(void)
  783. {   return;
  784. }
  785.  
  786. /* End of file "postlj.c" */
  787.