home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- *
- * NAME: pm.c
- *
- * DESCRIPTION: print text files in IBM (tm) manual format
- * on HP LaserJet III
- *
- * M O D I F I C A T I O N H I S T O R Y
- *
- * when who what
- * -------------------------------------------------------------------
- * 04/08/90 J. Alan Eldridge created
- * 04/10/90 JAE keeps all text in core now
- * 04/11/90 JAE adjusts size of buffers to fit
- * available heap space
- * page starts stored in array (so
- * can do random page access soon)
- * 04/12/90 JAE added random page access
- * 04/15/90 JAE added legal size paper support
- * added 2-pass printing in booklet
- * (manual) format
- *
- *********************************************************************/
-
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <stdlib.h>
-
- #include "strpool.h"
- #include "getargs.h"
-
- static char lpfont[] = "\033(10U\033(s0p16.67h8.5v0s0b0T";
-
- #define SIGNON "pm v. 1.20 by J. A. Eldridge"
- #define PDMSG "This program is placed in the public domain."
-
- #define PLEN48 (15*24) /* # of 1/48ths of inch per page */
-
- #define SCALE 100 /* scale factor for cpi */
- #define LET_WID 105 /* width of page in inches, letter */
- #define LEG_WID 130 /* width of page in inches, legal */
-
- #define PG_MAX 200 /* max # pages */
-
- char *outname = NULL;
- FILE *outfile = NULL;
-
- int cpi100, /* cpi x 100 */
- linechrs, /* # chrs per line */
- halfchrs, /* # chrs in half line */
- tlen = 60, /* text length */
- vm_idx = 8, /* vertical motion index */
- physlen = 60, /* physical page length */
- spread = 0, /* if !0, don't start file on right */
- sendfont = 1, /* send line printer font each page */
- divide = 0, /* put dividing line down middle */
- allflag = 1, /* print everything from beginning to end */
- legal = 0, /* legal size paper? */
- pwidth = LET_WID, /* page width */
- booklet = 0, /* reorder pages for booklet/manual */
- bpass = 0,
- dflag;
-
- STRADDR *adds; /* address of strings in pool */
- int pglist[PG_MAX]; /* page starts in adds array */
- int npgs = 1; /* page cntr, ends up # pgs + 2 */
- STRPOOL *spp; /* ptr to string pool */
- int scnt = 0; /* string count */
- int curs = 0; /* current string # */
- int maxlines; /* maximum # of lines allocated */
- int cpg = 1; /* current page # */
-
- /* functions to validate cpi, page length */
-
- int chkcpi(char*, int*);
- int chkpl(char*, int*);
- int chkbpass(char*, int*);
- int flame(char*, int*);
-
- /* the command line arguments */
-
- CMD_ARG pm_args[] = {
- "-pl", ARG_INT, &tlen, chkpl,
- "-o", ARG_STR, &outname, ARG_NOFUNC,
- "-cpi", ARG_INT|ARG_REQD, &cpi100, chkcpi,
- "-s", ARG_BOOL, &spread, ARG_NOFUNC,
- "-nf", ARG_BOOL, &sendfont, ARG_NOFUNC,
- "-div", ARG_BOOL, ÷, ARG_NOFUNC,
- "-pg", ARG_BOOL, &allflag, ARG_NOFUNC,
- "-L", ARG_BOOL, &legal, ARG_NOFUNC,
- "-B", ARG_BOOL, &booklet, chkbpass,
- "-b", ARG_INT, &bpass, chkbpass,
- "+d", ARG_BOOL, &dflag, flame
- };
-
- /* help msg for user */
-
- static char *umsg[] = {
- SIGNON,
- PDMSG,
- "",
- "print text files in landscape format (2 pages per sheet) on HP LJ III",
- "",
- "usage: pm -cpi cpi_x100 -pl page_len [-o out_file] [-nf][-s] [-L]",
- "\t[-B] [-b booklet_pass_number] input_file ...",
- "",
- "-o\toutput file name (default is standard output)",
- "-cpi\tcharacters per inch in the font you're using (X 100)",
- "-pl\tpage length in lines",
- "-nf\tdon't send line printer font codes",
- "-s\tspread files out (don't start a file on right half of page)",
- "-L\tlegal size paper (default is letter)",
- "-B\tprint in booklet format, both passes (double sided, 4 per sheet)",
- "-b\tprint in booklet format, either pass 1 or pass 2",
- "",
- "the filename '=tty' can be used to read from standard input",
- "",
- "this program will accept files with printer control codes (within",
- "\treason) and print them correctly",
- NULL
- };
-
- int
- flame(
- char *notused,
- int *ignored)
- {
- fprintf(stderr,
- "Dedicated to all those who have tried in vain to control a"
- " laser printer.\n");
- return 0;
- }
-
- /* process args, print help and die if error */
-
- void
- doargs(
- int *acp,
- char **av)
- {
- if (getargs(acp, av, ARG_CNT(pm_args), pm_args) != 0)
- usage(umsg, 20, 1);
- if (legal)
- pwidth = LEG_WID;
-
- }
-
- /* validate cpi for reasonable values */
-
- int
- chkcpi(
- char *opt,
- int *cpi)
- {
- return -(*cpi < 8*SCALE || * cpi > 25*SCALE);
- }
-
- /* validate page length and set vertical motion index */
-
- int
- chkpl(
- char *opt,
- int *pl)
- {
- if (*pl == 45) {
- vm_idx = 8;
- } else if (*pl == 60) {
- vm_idx = 6;
- } else if (*pl == 72) {
- vm_idx = 5;
- } else {
- vm_idx = PLEN48/(*pl);
- if (vm_idx < 3 || vm_idx > 48)
- return -1;
- }
- return 0;
- }
-
- int
- chkbpass(
- char *opt,
- int *arg)
- {
- if (!strcmp(opt, "-b")) {
- if (*arg == 1 || *arg == 2)
- return !(booklet = 1);
- else
- return -1;
- } else if (!strcmp(opt, "-B")) {
- bpass = 3;
- return 0;
- } else
- return -1; /* can't happen */
- }
-
- /* these don't need to be functions */
-
- #define hello() fprintf(stderr, "%s\n%s\n", SIGNON, PDMSG)
- #define die(s) fputs(s,stderr),exit(1)
-
- /* 'cause I don't want to type fprintf(outfile, ... */
-
- void
- ljprintf(
- char *fmt,
- ...)
- {
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(outfile, fmt, ap);
- va_end(ap);
- fflush(outfile);
- }
-
- /* open output file or assign to stdout */
-
- void
- openout(void)
- {
- if (outname) {
- outfile = fopen(outname, "w");
- if (!outfile)
- die("can't open output file");
- } else
- outfile = stdout;
- }
-
- #define closeout() fclose(outfile)
-
- /* macros to talk to laserjet */
-
- #define ljreset() ljprintf("\033E")
- #define ljland() ljprintf("\033&l1O")
- #define ljport() ljprintf("\033&l0O")
- #define ljtlen(n) ljprintf("\033&l%dF",n)
- #define ljlrmar(l,r) ljprintf("\033&a%dl%dM",l,r)
- #define ljgoto(r,c) ljprintf("\033&a%dr%dC",r,c)
- #define topleft() ljgoto(0,0)
- #define ljvmi(n) ljprintf("\033&l%dC",n);
- #define setvmi() ljvmi(vm_idx)
- #define ljeject() ljprintf("\033&l0H")
- #define ljclmar() ljprintf("\0339")
- #define ljnowrap() ljprintf("\033&s1C")
- #define ljlegal() ljprintf("\033&l3A")
-
- /* calculate margins etc */
-
- calc()
- {
- cpi100 += 5;
- linechrs = pwidth * (cpi100/10);
- halfchrs = linechrs/2;
- linechrs /= SCALE;
- halfchrs /= SCALE;
- physlen = PLEN48 / vm_idx;
- }
-
- /* which side are we on? */
-
- #define LEFT 0
- #define RIGHT (!LEFT)
-
- void
- set_margins(int which)
- {
- int base;
- int l, r;
-
- fprintf(stderr, "\nprinting page %3d of %3d\n", cpg++, npgs-2);
-
- if (which == LEFT) {
- ljreset();
- base = 0;
- } else
- base = halfchrs;
-
- l = base;
- r = base + halfchrs;
-
- if (which == LEFT)
- r -= 2;
- else
- l++;
-
- ljland();
- setvmi();
- ljtlen(tlen);
- ljclmar();
- ljlrmar(l,r);
- topleft();
- ljprintf("\r");
- ljnowrap();
- if (sendfont)
- ljprintf(lpfont);
- }
-
- void
- markpg(void)
- {
- if (npgs < 150) {
- pglist[npgs++] = scnt;
- } else {
- die("too many pages (> 150)");
- }
- }
-
- void
- rewrite()
- {
- long bufspace = (384L * 1024L);
-
- for (;;) {
- int nbufs;
-
- maxlines = bufspace / 50L;
- nbufs = bufspace / 0x4000L;
-
- spp = strpool_new(nbufs, 0x4000);
- adds = calloc(maxlines, sizeof(STRADDR));
- if (!spp || !adds) {
- if (bufspace < 0x10000L)
- die("can't alloc string space");
- else {
- if (spp) strpool_free(spp);
- if (adds) free(adds);
- bufspace -= 0x8000L;
- }
- } else
- break;
- }
- scnt = curs = 0;
- pglist[0] = 0;
- npgs = 1;
- }
-
- int firstln, lastln;
-
- void
- setpgs(
- int first,
- int last)
- {
- if (first < 1)
- first = 1;
- if (last > npgs - 1)
- last = npgs - 1;
-
- cpg = first;
- firstln = pglist[first - 1];
- lastln = pglist[last - 1];
- curs = firstln;
- }
-
- char *
- nxtln(void)
- {
- if (curs < lastln) {
- if (kbhit() && (getch(),askyn(1, "\n*** Abort printing"))) {
- ljeject();
- ljreset();
- fclose(outfile);
- exit(1);
- }
- return strpool_get(spp, adds[curs++], NULL);
- } else
- return NULL;
- }
-
- void
- addln(char *s)
- {
- int ret;
-
- if (scnt >= maxlines
- || strpool_put(spp, strlen(s) + 1, s, adds[scnt]) != 0) {
- die("addln() failed");
- } else
- scnt++;
- }
-
- #define FORMFEED 12
-
- static int
- gl (fp, s, lim, ffp)
- FILE *fp;
- char s[];
- int lim;
- int *ffp;
- {
- static int need_newpage = 0;
-
- int c, i;
-
- if (need_newpage) {
- need_newpage = 0;
- s[0] = FORMFEED;
- s[1] = 0;
- return 1;
- }
-
- for (i = 0; i < lim - 2 && (c = getc(fp)) != EOF
- && c != '\n' && c != FORMFEED; ++i)
- s[i] = c;
- /*
- this handles the pathological case where we filled
- the buffer and the next character is a newline
- */
- if (c != '\n' && c != FORMFEED && c != EOF) {
- int ch = getc(fp);
-
- if (ch == '\n')
- c = '\n';
- else
- ungetc(ch, fp);
- }
- if (c == '\n' || ((c == FORMFEED || c == EOF) && i > 0))
- s[i++] = '\n';
- if (c == FORMFEED) {
- *ffp = 1;
- need_newpage = 1;
- }
- s[i] = 0;
- return i;
- }
-
- int
- fgetline(
- FILE *fp,
- char *buf,
- int lim)
- {
- int got_ff;
- int nchars;
-
- do {
- got_ff = 0;
- nchars = gl(fp, buf, lim, &got_ff);
- } while (nchars == 0 && got_ff);
- return nchars;
- }
-
- char inbuf[3000];
-
- void
- zapnl(char *buf)
- {
- int len = strlen(buf);
-
- if (len > 0)
- if (buf[len-1] == '\n')
- buf[len-1] = 0;
- }
-
- void
- readfile(char *fn)
- {
- static int side = LEFT;
-
- int lines;
- int dots, cnt;
- int ff;
- FILE *infile;
-
- if (!strcmp(fn, "=tty")) {
- infile = stdin;
- dots = 0;
- } else {
- infile = fopen(fn, "r");
- if (!infile) {
- fprintf(stderr, "can't open file \"%s\"!\n", fn);
- return;
- }
- fprintf(stderr, "reading \"%s\"\n", fn);
- dots = 1;
- }
- ff = lines = cnt = 0;
- while (fgetline(infile, inbuf, sizeof(inbuf)-1)) {
- if (dots && cnt++ % 4)
- putc('.', stderr);
- if (ff = inbuf[0] == FORMFEED) {
- addln("\377");
- lines = tlen;
- } else {
- if (lines == tlen) {
- markpg();
- side = !side;
- lines = 0;
- }
- if (++lines == tlen)
- zapnl(inbuf);
- addln(inbuf);
- }
- }
- if (dots) {
- fclose(infile);
- putc('\n', stderr);
- }
- if (lines < tlen)
- addln("\377");
- if (!ff)
- markpg();
- if (side == LEFT) {
- if (spread) {
- addln("\377");
- markpg();
- } else
- side = RIGHT;
- }
- markpg();
- }
-
- void
- printtxt(int eject)
- {
- static int side = LEFT;
- int lines, cnt;
- char *ln;
-
- cnt = lines = 0;
- set_margins(side);
- while (ln = nxtln()) {
- if (cnt++ % 4)
- putc('.', stderr);
- if (lines == tlen) {
- if (side == RIGHT)
- ljeject();
- side = !side;
- set_margins(side);
- lines = 0;
- }
- if ((ln[0] & 0377) == 0377) {
- if (side == RIGHT && divide) {
- while (++lines < tlen)
- ljprintf("|\n");
- ljprintf("|");
- } else
- lines = tlen;
- } else {
- ++lines;
- if (side == RIGHT && divide)
- ljprintf("| ");
- else
- ljprintf(" ");
- ljprintf("%s", ln);
- }
- }
- putc('\n', stderr);
- if (side == LEFT && divide) {
- int n;
-
- set_margins(RIGHT);
- for (n = 0; n < tlen-1; n++)
- ljprintf("|\n");
- ljprintf("|");
- }
- if (eject)
- side = RIGHT;
- if (side == RIGHT)
- ljeject();
- side = !side;
- }
-
- void
- printall(void)
- {
- setpgs(1, npgs-1);
- printtxt(0);
- }
-
- void
- printsome(void)
- {
- fprintf(stderr, "\nprintsome() is not implemented yet.\n");
- }
-
- void
- printbklt(void)
- {
- int smax,
- sheet,
- lpg,
- rpg,
- pgnum = npgs - 2;
-
- while (pgnum % 4) {
- addln("\377");
- markpg();
- pgnum++;
- }
-
- smax = pgnum / 4;
-
- if (bpass & 1) {
- fprintf(stderr, "booklet printing, pass 1\n");
- for (sheet = 0; sheet < smax; sheet++) {
- rpg = sheet * 2 + 1;
- lpg = pgnum - sheet * 2;
- setpgs(lpg, lpg+1);
- printtxt(0);
- setpgs(rpg, rpg+1);
- printtxt(1);
- }
- }
-
- if (bpass == 3 && !askyn(1, "Ready for booklet printing, pass 2"))
- return;
-
- if (bpass & 2) {
- fprintf(stderr, "booklet printing, pass 2\n");
- for (sheet = smax - 1; sheet >= 0; sheet--) {
- lpg = sheet * 2 + 2;
- rpg = pgnum - (sheet * 2 + 1);
- setpgs(lpg, lpg+1);
- printtxt(0);
- setpgs(rpg, rpg+1);
- printtxt(1);
- }
- }
- }
-
- main(
- int ac,
- char **av)
- {
- doargs(&ac, av);
- hello();
- openout();
- calc();
- ljreset();
- rewrite();
- while (--ac > 0)
- readfile(*++av);
- fprintf(stderr, "%d logical pages (%d physical %s)\n",
- npgs-2, (npgs-1)/2, (npgs-1)/2 > 1 ? "pages" : "page");
- if (legal)
- ljlegal();
- if (booklet)
- printbklt();
- else if (allflag)
- printall();
- else
- printsome();
- ljreset();
- closeout();
- }
-
-