home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / LASER / PM120.ZIP / PM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-15  |  15.1 KB  |  649 lines

  1. /**********************************************************************
  2.  *  
  3.  *  NAME:           pm.c
  4.  *  
  5.  *  DESCRIPTION:    print text files in IBM (tm) manual format
  6.  *                  on HP LaserJet III
  7.  *  
  8.  *  M O D I F I C A T I O N   H I S T O R Y
  9.  *
  10.  *  when        who                 what
  11.  *  -------------------------------------------------------------------
  12.  *  04/08/90    J. Alan Eldridge    created
  13.  *  04/10/90    JAE                 keeps all text in core now
  14.  *  04/11/90    JAE                 adjusts size of buffers to fit
  15.  *                                  available heap space
  16.  *                                  page starts stored in array (so
  17.  *                                  can do random page access soon)
  18.  *  04/12/90    JAE                 added random page access
  19.  *  04/15/90    JAE                 added legal size paper support
  20.  *                                  added 2-pass printing in booklet
  21.  *                                  (manual) format
  22.  *  
  23.  *********************************************************************/
  24.  
  25. #include <stdio.h>
  26. #include <stdarg.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29.  
  30. #include "strpool.h"
  31. #include "getargs.h"
  32.  
  33. static char lpfont[] = "\033(10U\033(s0p16.67h8.5v0s0b0T";
  34.  
  35. #define SIGNON  "pm v. 1.20 by J. A. Eldridge"
  36. #define PDMSG   "This program is placed in the public domain."
  37.  
  38. #define PLEN48  (15*24) /* # of 1/48ths of inch per page */
  39.  
  40. #define SCALE   100 /* scale factor for cpi */
  41. #define LET_WID 105 /* width of page in inches, letter */
  42. #define LEG_WID 130 /* width of page in inches, legal */
  43.  
  44. #define PG_MAX  200     /* max # pages */
  45.  
  46. char    *outname = NULL;
  47. FILE    *outfile = NULL;
  48.  
  49. int     cpi100,         /* cpi x 100 */
  50.         linechrs,       /* # chrs per line */
  51.         halfchrs,       /* # chrs in half line */
  52.         tlen = 60,      /* text length */
  53.         vm_idx = 8,     /* vertical motion index */
  54.         physlen = 60,   /* physical page length */
  55.         spread = 0,     /* if !0, don't start file on right */
  56.         sendfont = 1,   /* send line printer font each page */
  57.         divide = 0,     /* put dividing line down middle */
  58.         allflag = 1,    /* print everything from beginning to end */
  59.         legal = 0,      /* legal size paper? */
  60.         pwidth = LET_WID,   /* page width */
  61.         booklet = 0,    /* reorder pages for booklet/manual */
  62.         bpass = 0,
  63.         dflag;
  64.                 
  65. STRADDR *adds;          /* address of strings in pool */
  66. int     pglist[PG_MAX]; /* page starts in adds array */
  67. int     npgs = 1;       /* page cntr, ends up # pgs + 2 */
  68. STRPOOL *spp;           /* ptr to string pool */
  69. int     scnt = 0;       /* string count */
  70. int     curs = 0;       /* current string # */
  71. int     maxlines;       /* maximum # of lines allocated */
  72. int     cpg = 1;        /* current page # */
  73.  
  74. /* functions to validate cpi, page length */
  75.  
  76. int chkcpi(char*, int*);
  77. int chkpl(char*, int*);
  78. int chkbpass(char*, int*);
  79. int flame(char*, int*);
  80.  
  81. /* the command line arguments */
  82.  
  83. CMD_ARG pm_args[] =  {
  84.     "-pl",  ARG_INT,            &tlen,      chkpl,
  85.     "-o",   ARG_STR,            &outname,   ARG_NOFUNC,
  86.     "-cpi", ARG_INT|ARG_REQD,   &cpi100,    chkcpi,
  87.     "-s",   ARG_BOOL,           &spread,    ARG_NOFUNC,
  88.     "-nf",  ARG_BOOL,           &sendfont,  ARG_NOFUNC,
  89.     "-div", ARG_BOOL,           ÷,    ARG_NOFUNC,
  90.     "-pg",  ARG_BOOL,           &allflag,   ARG_NOFUNC,
  91.     "-L",   ARG_BOOL,           &legal,     ARG_NOFUNC,
  92.     "-B",   ARG_BOOL,           &booklet,   chkbpass,
  93.     "-b",   ARG_INT,            &bpass,     chkbpass,
  94.     "+d",   ARG_BOOL,           &dflag,     flame
  95. };
  96.  
  97. /* help msg for user */
  98.  
  99. static char *umsg[] = {
  100.     SIGNON,
  101.     PDMSG,
  102.     "",
  103.     "print text files in landscape format (2 pages per sheet) on HP LJ III",
  104.     "",
  105.     "usage: pm -cpi cpi_x100 -pl page_len [-o out_file] [-nf][-s] [-L]",
  106.     "\t[-B] [-b booklet_pass_number] input_file ...",
  107.     "",
  108.     "-o\toutput file name (default is standard output)",
  109.     "-cpi\tcharacters per inch in the font you're using (X 100)",
  110.     "-pl\tpage length in lines",
  111.     "-nf\tdon't send line printer font codes",
  112.     "-s\tspread files out (don't start a file on right half of page)",
  113.     "-L\tlegal size paper (default is letter)",
  114.     "-B\tprint in booklet format, both passes (double sided, 4 per sheet)",
  115.     "-b\tprint in booklet format, either pass 1 or pass 2",
  116.     "",
  117.     "the filename '=tty' can be used to read from standard input",
  118.     "",
  119.     "this program will accept files with printer control codes (within",
  120.     "\treason) and print them correctly",
  121.     NULL
  122. };        
  123.  
  124. int
  125. flame(
  126.     char    *notused,
  127.     int     *ignored)
  128. {
  129.     fprintf(stderr,
  130.         "Dedicated to all those who have tried in vain to control a"
  131.         " laser printer.\n");
  132.     return 0;
  133. }
  134.  
  135. /* process args, print help and die if error */
  136.  
  137. void
  138. doargs(
  139.     int     *acp,
  140.     char    **av)
  141. {
  142.     if (getargs(acp, av, ARG_CNT(pm_args), pm_args) != 0)
  143.         usage(umsg, 20, 1);
  144.     if (legal)
  145.         pwidth = LEG_WID;
  146.             
  147. }
  148.  
  149. /* validate cpi for reasonable values */
  150.  
  151. int
  152. chkcpi(
  153.     char    *opt,
  154.     int     *cpi)
  155. {
  156.     return -(*cpi < 8*SCALE || * cpi > 25*SCALE);
  157. }
  158.  
  159. /* validate page length and set vertical motion index */
  160.  
  161. int
  162. chkpl(
  163.     char    *opt,
  164.     int     *pl)
  165. {
  166.     if (*pl == 45) {
  167.         vm_idx = 8;
  168.     } else if (*pl == 60) {
  169.         vm_idx = 6;
  170.     } else if (*pl == 72) {
  171.         vm_idx = 5;
  172.     } else {
  173.         vm_idx = PLEN48/(*pl);
  174.         if (vm_idx < 3 || vm_idx > 48)
  175.             return -1;
  176.     }
  177.     return 0;
  178. }
  179.  
  180. int
  181. chkbpass(
  182.     char    *opt,
  183.     int     *arg)
  184. {
  185.     if (!strcmp(opt, "-b")) {
  186.         if (*arg == 1 || *arg == 2)
  187.             return !(booklet = 1);
  188.         else
  189.             return -1;
  190.     } else if (!strcmp(opt, "-B")) {
  191.         bpass = 3;
  192.         return 0;
  193.     } else
  194.         return -1;  /* can't happen */
  195. }
  196.  
  197. /* these don't need to be functions */
  198.  
  199. #define hello() fprintf(stderr, "%s\n%s\n", SIGNON, PDMSG)
  200. #define die(s)  fputs(s,stderr),exit(1)
  201.  
  202. /* 'cause I don't want to type fprintf(outfile, ... */
  203.  
  204. void
  205. ljprintf(
  206.     char    *fmt,
  207.     ...)
  208. {
  209.     va_list ap;
  210.     
  211.     va_start(ap, fmt);
  212.     vfprintf(outfile, fmt, ap);
  213.     va_end(ap);
  214.     fflush(outfile);
  215. }
  216.  
  217. /* open output file or assign to stdout */
  218.  
  219. void
  220. openout(void)
  221. {
  222.     if (outname) {
  223.         outfile = fopen(outname, "w");
  224.         if (!outfile)
  225.             die("can't open output file");
  226.     } else
  227.         outfile = stdout;
  228. }
  229.  
  230. #define closeout() fclose(outfile)
  231.  
  232. /* macros to talk to laserjet */
  233.  
  234. #define ljreset()       ljprintf("\033E")
  235. #define ljland()        ljprintf("\033&l1O")
  236. #define ljport()        ljprintf("\033&l0O")
  237. #define ljtlen(n)       ljprintf("\033&l%dF",n)
  238. #define ljlrmar(l,r)    ljprintf("\033&a%dl%dM",l,r)
  239. #define ljgoto(r,c)     ljprintf("\033&a%dr%dC",r,c)
  240. #define topleft()       ljgoto(0,0)
  241. #define ljvmi(n)        ljprintf("\033&l%dC",n);
  242. #define setvmi()        ljvmi(vm_idx)
  243. #define ljeject()       ljprintf("\033&l0H")
  244. #define ljclmar()       ljprintf("\0339")
  245. #define ljnowrap()      ljprintf("\033&s1C")
  246. #define ljlegal()       ljprintf("\033&l3A")
  247.  
  248. /* calculate margins etc */
  249.  
  250. calc()
  251. {
  252.     cpi100 += 5;
  253.     linechrs = pwidth * (cpi100/10);
  254.     halfchrs = linechrs/2;
  255.     linechrs /= SCALE;
  256.     halfchrs /= SCALE;
  257.     physlen = PLEN48 / vm_idx;
  258. }    
  259.     
  260. /* which side are we on? */
  261.  
  262. #define LEFT    0
  263. #define RIGHT   (!LEFT)
  264.  
  265. void
  266. set_margins(int which)
  267. {
  268.     int base;
  269.     int l, r;
  270.      
  271.     fprintf(stderr, "\nprinting page %3d of %3d\n", cpg++, npgs-2);
  272.     
  273.     if (which == LEFT) {
  274.         ljreset();
  275.         base = 0;
  276.     } else
  277.         base = halfchrs;
  278.           
  279.     l = base;
  280.     r = base + halfchrs;
  281.     
  282.     if (which == LEFT)
  283.         r -= 2;
  284.     else 
  285.         l++;
  286.  
  287.     ljland();
  288.     setvmi();
  289.     ljtlen(tlen);
  290.     ljclmar();   
  291.     ljlrmar(l,r);
  292.     topleft();
  293.     ljprintf("\r");
  294.     ljnowrap();
  295.     if (sendfont)
  296.         ljprintf(lpfont);
  297. }
  298.  
  299. void
  300. markpg(void)
  301. {
  302.     if (npgs < 150) {
  303.         pglist[npgs++] = scnt;
  304.     } else {
  305.         die("too many pages (> 150)");
  306.     }
  307. }
  308.  
  309. void
  310. rewrite()
  311. {
  312.     long    bufspace = (384L * 1024L);
  313.  
  314.     for (;;) {
  315.         int         nbufs;
  316.         
  317.         maxlines = bufspace / 50L;
  318.         nbufs = bufspace / 0x4000L;    
  319.  
  320.         spp = strpool_new(nbufs, 0x4000);
  321.         adds = calloc(maxlines, sizeof(STRADDR));
  322.         if (!spp || !adds) {
  323.             if (bufspace < 0x10000L)
  324.                 die("can't alloc string space");
  325.             else {
  326.                 if (spp) strpool_free(spp);
  327.                 if (adds) free(adds);
  328.                 bufspace -= 0x8000L;
  329.             }
  330.         } else
  331.             break;
  332.     }
  333.     scnt = curs = 0;            
  334.     pglist[0] = 0;
  335.     npgs = 1;
  336. }
  337.  
  338. int firstln, lastln;
  339.  
  340. void
  341. setpgs(
  342.     int first,
  343.     int last)
  344. {
  345.     if (first < 1)
  346.         first = 1;
  347.     if (last > npgs - 1)
  348.         last = npgs - 1;
  349.         
  350.     cpg = first;
  351.     firstln = pglist[first - 1];
  352.     lastln = pglist[last - 1];
  353.     curs = firstln;
  354. }
  355.  
  356. char *
  357. nxtln(void)
  358. {
  359.     if (curs < lastln) {
  360.         if (kbhit() && (getch(),askyn(1, "\n*** Abort printing"))) {
  361.            ljeject();
  362.            ljreset();
  363.            fclose(outfile);
  364.            exit(1);
  365.         }
  366.         return strpool_get(spp, adds[curs++], NULL);
  367.     } else
  368.         return NULL;
  369. }
  370.  
  371. void
  372. addln(char *s)
  373. {
  374.     int ret;
  375.  
  376.     if (scnt >= maxlines
  377.         || strpool_put(spp, strlen(s) + 1, s, adds[scnt]) != 0) {
  378.         die("addln() failed");
  379.     } else
  380.         scnt++;
  381. }    
  382.  
  383. #define FORMFEED 12
  384.  
  385. static int
  386. gl (fp, s, lim, ffp)
  387. FILE  *fp;
  388. char  s[];
  389. int   lim;
  390. int   *ffp;
  391. {
  392.     static int need_newpage = 0;    
  393.  
  394.     int c, i;
  395.  
  396.     if (need_newpage) {
  397.         need_newpage = 0;
  398.         s[0] = FORMFEED;
  399.         s[1] = 0;
  400.         return 1;
  401.     }
  402.  
  403.     for (i = 0; i < lim - 2 && (c = getc(fp)) != EOF 
  404.         && c != '\n' && c != FORMFEED; ++i)
  405.         s[i] = c;
  406.     /* 
  407.         this handles the pathological case where we filled
  408.         the buffer and the next character is a newline
  409.     */        
  410.     if (c != '\n' && c != FORMFEED && c != EOF) {
  411.         int ch = getc(fp);
  412.         
  413.         if (ch == '\n')
  414.             c = '\n';
  415.         else
  416.             ungetc(ch, fp);
  417.     }
  418.     if (c == '\n' || ((c == FORMFEED || c == EOF) && i > 0))
  419.         s[i++] = '\n';
  420.     if (c == FORMFEED) {
  421.         *ffp = 1;
  422.         need_newpage = 1;
  423.     }
  424.     s[i] = 0;
  425.     return i;
  426. }
  427.  
  428. int
  429. fgetline(
  430.     FILE    *fp,
  431.     char    *buf,
  432.     int     lim)
  433. {
  434.     int got_ff;
  435.     int nchars;
  436.    
  437.     do {
  438.         got_ff = 0;
  439.         nchars = gl(fp, buf, lim, &got_ff);
  440.     } while (nchars == 0 && got_ff);
  441.     return nchars;
  442. }
  443.    
  444. char  inbuf[3000];
  445.  
  446. void
  447. zapnl(char *buf)
  448. {
  449.    int len = strlen(buf);
  450.    
  451.    if (len > 0)
  452.       if (buf[len-1] == '\n')
  453.          buf[len-1] = 0;
  454. }
  455.  
  456. void
  457. readfile(char *fn)
  458. {
  459.     static int side = LEFT;
  460.    
  461.     int lines;
  462.     int dots, cnt;
  463.     int ff;
  464.     FILE  *infile;
  465.  
  466.     if (!strcmp(fn, "=tty")) {
  467.         infile = stdin;
  468.         dots = 0;
  469.     } else {
  470.         infile = fopen(fn, "r");
  471.         if (!infile) {
  472.             fprintf(stderr, "can't open file \"%s\"!\n", fn);
  473.             return;
  474.         }
  475.         fprintf(stderr, "reading \"%s\"\n", fn);
  476.         dots = 1;
  477.     }
  478.     ff = lines = cnt = 0;
  479.     while (fgetline(infile, inbuf, sizeof(inbuf)-1)) {
  480.         if (dots && cnt++ % 4)
  481.             putc('.', stderr);
  482.         if (ff = inbuf[0] == FORMFEED) {
  483.             addln("\377");
  484.             lines = tlen;
  485.         } else {
  486.             if (lines == tlen) {
  487.                 markpg();
  488.                 side = !side;
  489.                 lines = 0;
  490.             }
  491.             if (++lines == tlen)
  492.                 zapnl(inbuf);
  493.             addln(inbuf);
  494.         }
  495.     }
  496.     if (dots) {
  497.         fclose(infile);
  498.         putc('\n', stderr);
  499.     }
  500.     if (lines < tlen)
  501.         addln("\377");
  502.     if (!ff)
  503.         markpg();
  504.     if (side == LEFT) {
  505.         if (spread) {
  506.             addln("\377");
  507.             markpg();
  508.         } else
  509.             side = RIGHT;
  510.     }
  511.     markpg();
  512. }
  513.  
  514. void
  515. printtxt(int eject)
  516. {
  517.     static int  side = LEFT;
  518.     int         lines, cnt;
  519.     char        *ln;
  520.           
  521.     cnt = lines = 0;
  522.     set_margins(side);
  523.     while (ln = nxtln()) {
  524.         if (cnt++ % 4)
  525.             putc('.', stderr);
  526.         if (lines == tlen) {
  527.             if (side == RIGHT)
  528.                 ljeject();
  529.             side = !side;
  530.             set_margins(side);
  531.             lines = 0;
  532.         }
  533.         if ((ln[0] & 0377) == 0377) {
  534.             if (side == RIGHT && divide) {
  535.                 while (++lines < tlen)
  536.                     ljprintf("|\n");
  537.                 ljprintf("|");
  538.             } else
  539.                 lines = tlen;   
  540.         } else {
  541.             ++lines;
  542.             if (side == RIGHT && divide)
  543.                 ljprintf("| ");
  544.             else
  545.                 ljprintf("  ");
  546.             ljprintf("%s", ln);
  547.         }
  548.     }
  549.     putc('\n', stderr);
  550.     if (side == LEFT && divide) {
  551.         int n;
  552.         
  553.         set_margins(RIGHT);
  554.         for (n = 0; n < tlen-1; n++)
  555.             ljprintf("|\n");
  556.         ljprintf("|");
  557.     }
  558.     if (eject)
  559.         side = RIGHT;
  560.     if (side == RIGHT)
  561.         ljeject();
  562.     side = !side;
  563. }
  564.  
  565. void
  566. printall(void)
  567. {
  568.    setpgs(1, npgs-1);
  569.    printtxt(0);
  570. }   
  571.  
  572. void
  573. printsome(void)
  574. {
  575.    fprintf(stderr, "\nprintsome() is not implemented yet.\n");
  576. }
  577.  
  578. void
  579. printbklt(void)
  580. {
  581.     int smax, 
  582.         sheet, 
  583.         lpg, 
  584.         rpg,
  585.         pgnum = npgs - 2;
  586.     
  587.     while (pgnum % 4) {
  588.         addln("\377");
  589.         markpg();
  590.         pgnum++;
  591.     }
  592.  
  593.     smax = pgnum / 4;
  594.     
  595.     if (bpass & 1) {
  596.         fprintf(stderr, "booklet printing, pass 1\n");
  597.         for (sheet = 0; sheet < smax; sheet++) {
  598.             rpg = sheet * 2 + 1;
  599.             lpg = pgnum - sheet * 2;
  600.             setpgs(lpg, lpg+1);
  601.             printtxt(0);
  602.             setpgs(rpg, rpg+1);
  603.             printtxt(1);
  604.         }
  605.     }
  606.     
  607.     if (bpass == 3 && !askyn(1, "Ready for booklet printing, pass 2"))
  608.             return;
  609.         
  610.     if (bpass & 2) {
  611.         fprintf(stderr, "booklet printing, pass 2\n");
  612.         for (sheet = smax - 1; sheet >= 0; sheet--) {
  613.             lpg = sheet * 2 + 2;
  614.             rpg = pgnum - (sheet * 2 + 1);
  615.             setpgs(lpg, lpg+1);
  616.             printtxt(0);
  617.             setpgs(rpg, rpg+1);
  618.             printtxt(1);
  619.         }
  620.     }
  621. }
  622.  
  623. main(
  624.     int     ac,
  625.     char    **av)
  626. {
  627.     doargs(&ac, av);
  628.     hello();
  629.     openout();
  630.     calc();
  631.     ljreset();
  632.     rewrite();
  633.     while (--ac > 0)
  634.         readfile(*++av);
  635.     fprintf(stderr, "%d logical pages (%d physical %s)\n",
  636.         npgs-2, (npgs-1)/2, (npgs-1)/2 > 1 ? "pages" : "page");
  637.     if (legal)
  638.         ljlegal();
  639.     if (booklet)
  640.         printbklt();
  641.     else if (allflag)
  642.        printall();
  643.     else
  644.         printsome();
  645.     ljreset();
  646.     closeout();
  647. }
  648.             
  649.