|
|
1.1 root 1: /*
2: * hp.c
3: * 11/13/90
4: * Hewlett Packard LaserJet printer filter.
5: * Translate page format and nroff font information
6: * into HP LaserJet printer escape sequences (PCL).
7: * Usage: hp [-acflr] [-in] [-pn] [-tn] [file ...]
8: * Options:
9: * -a Use HP font acute accent character for '\''; default is '\''.
10: * -c Font cartridge not available, use underline for italics.
11: * -f [Archaic] Print pages in normal order; this is now the default.
12: * -in Set left margin (indent) to n; default is 0.
13: * -l Print in landscape mode; default is portrait mode.
14: * -pn Set text length to n; default is NLINES, i.e. 66.
15: * -r Print pages in reverse order (for LaserJet I).
16: * [Writes to temp FILE 'output', then readback() rewrites
17: * temp file to stdout with pages reversed.]
18: * -tn Set top margin to n; default is 0.
19: * Exit status is 0 if successful, 1 if error, 2 if interrupted.
20: *
21: * Edit history:
22: * 3/21/85 (jtk) -- Changed so that pages were printed in reverse order,
23: * and fixed bug where trailing lines with only
24: * non-blank character were deleted.
25: * 4/09/85 (ella) -- Changed so that pages were printed in
26: * the landscape mode with the pitch 16.66, and
27: * fixed bug where underlining in the landscape mode
28: * and/or !cartridge wasn't ever terminated.
29: * Incorporated rma's fix (-a option) to reflect the
30: * manual page and properly process acute accents:
31: * default: straight (apostrophe), with -a: slanted
32: * (single quote).
33: * Included all available options into Usage message.
34: * 10/31/90 (norm) -- fixed the brain damage regarding
35: * formfeeds. Change default to printing pages in
36: * order since almost all printers do. Close any
37: * files that we open. Guess that shows how much testing
38: * was done by the author...
39: * 11/7/90 (steve) -- Reordered and rewrote text extensively
40: * for legibility, hopefully no substantive changes.
41: */
42:
43: #include <stdio.h>
44: #include <signal.h>
45:
46: extern long ftell();
47:
48: /* Miscellany. */
49: #define VERSION "1.3"
50: #define ACCENTACUTE 0xA8
51: #define ACCENTGRAVE 0xA9
52: #define LINESZ 512
53: #define NLINES 66
54: #define NPAGES 1000
55: #define USAGEMSG "Usage: hp [ -acflr ] [ -in ] [ -pn ] [ -tn ] [ file ... ]"
56:
57: /* Fonts. */
58: #define ROMAN_F 0 /* all except below means Roman */
59: #define BOLD_F 1 /* "x\bx" means bold 'x' */
60: #define ITALIC_F 2 /* "_\bx" means italic '_' */
61:
62: /* HP Printer Control Language (PCL) commands. */
63: /* These are printf() format strings, some require additional arguments. */
64: #define HMOVEFWD "\033&a+%dH"
65: #define HMOVEBACK "\033&a-%dH"
66: #define LANDSCAPE "\033&l%dO" /* arg 0==portrait, 1==landscape */
67: #define LEFTMARGIN "\033&a%dL"
68: #define LINESPACING "\033&l%dD"
69: #define MOVETOCOL "\033&a%dC"
70: #define PAGELENGTH "\033&l%dP"
71: #define PITCH16 "\033(s16.66H" /* pitch 16.66 cpi */
72: #define RESET "\033E"
73: #define STROKEWEIGHT "\033(s%dB"
74: #define STYLE "\033(s%dS"
75: #define STYLEWEIGHT "\033(s%ds%dB"
76: #define TEXTLENGTH "\033&l%dF"
77: #define TOPMARGIN "\033&l%dE"
78: #define UNDEROFF "\033&d@"
79: #define UNDERON "\033&dD"
80:
81: /* Forward. */
82: #if 0
83: void debug();
84: #endif
85: void done();
86: void fakebold();
87: void fatal();
88: int hasFF();
89: void initialize();
90: void newfont();
91: int nonblank();
92: void printfile();
93: void printline();
94: void readback();
95: void trap();
96: void usage();
97:
98: /* Globals. */
99: int aflag; /* Accent flag */
100: char *argv0; /* Command name for error messages */
101: int cartridge = 1; /* Font cartridge is available */
102: int font = ROMAN_F; /* Current font */
103: int landscape; /* 0 for portrait mode, 1 for landscape */
104: int leftmargin; /* Left margin */
105: int linespacing = 6; /* Vertical lines per inch */
106: int nfiles; /* Number of files to print */
107: int npages; /* Number of pages marked on input */
108: FILE *output = NULL; /* FILE containing unreversed pages */
109: char page[NLINES][LINESZ]; /* Current page buffer */
110: long pageaddr[NPAGES]; /* Seek pointers to top of output pages */
111: int quit; /* Signal to interrupt program */
112: int rflag; /* Reverse page order */
113: char tempfile[20]; /* Temporary file name */
114: int textlength = NLINES; /* Text length -- must satisfy */
115: /* textlength <= NLINES-topmargin */
116: int topmargin; /* Top margin */
117:
118: main(argc, argv) int argc; char *argv[];
119: {
120: /* Process arguments. */
121: argv0 = argv[0];
122: argc--;
123: argv++;
124: while (argc > 0) {
125: switch(**argv) {
126: case '-':
127: switch(*++*argv) {
128: case 'a':
129: aflag = 1;
130: break;
131: case 'c':
132: cartridge = 0;
133: break;
134: case 'f':
135: /* Recognized for historical reasons, ignore. */
136: break;
137: case 'i':
138: leftmargin = atoi(++*argv);
139: break;
140: case 'l':
141: landscape = 1;
142: linespacing = 8;
143: break;
144: case 'p':
145: textlength = atoi(++*argv);
146: break;
147: case 'r':
148: rflag = 1;
149: break;
150: case 't':
151: topmargin = atoi(++*argv);
152: break;
153: case 'V':
154: fprintf(stderr, "%s: V%s\n", argv0, VERSION);
155: break;
156: default:
157: usage();
158: break;
159: }
160: break;
161: default:
162: if (nfiles++ == 0)
163: initialize();
164: printfile(*argv);
165: break;
166: }
167: argv++;
168: argc--;
169: }
170:
171: /* If no command line files, process stdin. */
172: if (nfiles == 0) {
173: initialize();
174: printfile(NULL);
175: }
176:
177: /* Done. */
178: if (rflag)
179: readback();
180: done(0);
181: }
182:
183: #if 0
184: /*
185: * Print debugging output to file "hp.db".
186: */
187: /* VARARGS */
188: void
189: debug(s) char *s;
190: {
191: register FILE *fp;
192:
193: if ((fp = fopen("hp.db", "ar")) == NULL)
194: return;
195: fprintf(fp, "hp: %r\n" &s);
196: fclose(fp);
197: }
198: #endif
199:
200: /*
201: * Finish up. Remove temporary file if it has been opened, then exit.
202: */
203: void
204: done(status) int status;
205: {
206: printf(RESET);
207: if (output != NULL) {
208: fclose(output);
209: if (output != stdout)
210: unlink(tempfile);
211: }
212: exit(status);
213: }
214:
215: /*
216: * Fake boldface of given character when font not available.
217: */
218: void
219: fakebold(c) register int c;
220: {
221: register int d;
222:
223: if (font != ROMAN_F)
224: newfont(ROMAN_F); /* terminate previous font */
225: d = (landscape) ? 7 : 8; /* decipoint distance */
226: putc(c, output); /* print it */
227: fprintf(output, MOVETOCOL, -1); /* move back one column */
228: fprintf(output, HMOVEFWD, d); /* and forward d decipoints */
229: putc(c, output); /* print it again */
230: fprintf(output, HMOVEBACK, d); /* and move back d decipoints */
231: }
232:
233: /*
234: * Print a fatal error message and die.
235: */
236: /* VARARGS */
237: void
238: fatal(s) char *s;
239: {
240: fprintf(stderr, "%s: %r\n", argv0, &s);
241: done(1);
242: }
243:
244: /*
245: * Test whether string s contains a formfeed.
246: */
247: int
248: hasFF(s) register char *s;
249: {
250: register char c;
251:
252: while (c = *s++)
253: if (c == '\f')
254: return 1;
255: return 0;
256: }
257:
258: /*
259: * Set interrupt trap and initialize the printer.
260: * Open temporary file if rflag is specified,
261: * otherwise output just goes to stdout.
262: */
263: void
264: initialize()
265: {
266: /* Trap SIGINT to set quit flag. */
267: signal(SIGINT, trap);
268:
269: /* HP initialization. */
270: printf(RESET);
271: if (landscape)
272: printf(PITCH16);
273: printf(LANDSCAPE, landscape);
274: printf(PAGELENGTH, NLINES);
275: printf(LINESPACING, linespacing);
276: printf(TOPMARGIN, topmargin);
277: printf(TEXTLENGTH, textlength);
278: printf(LEFTMARGIN, leftmargin);
279:
280: /* Initialize output file. */
281: if (quit)
282: done(2);
283: if (rflag) {
284: sprintf(tempfile, "/tmp/hptmp.%d", getpid());
285: if ((output = fopen(tempfile, "wr")) == NULL)
286: fatal("cannot open temporary file \"%s\"", tempfile);
287: } else
288: output = stdout;
289: }
290:
291: /*
292: * Change to a new font.
293: * For each of the three fonts (ROMAN_F, BOLD_F, ITALIC_F),
294: * this routine prints the font escape appropriate to the given configuration.
295: * There are currently four possible printer configurations:
296: * normal portrait && cartridge
297: * -l landscape && cartridge
298: * -c portrait && no cartridge
299: * -c -l landscape && no cartridge
300: * In the first case, do bold and italic with style and weight changes.
301: * bold is faked from printline() per-character in the other cases,
302: * italic is underlined Roman in the other cases.
303: */
304: void
305: newfont(new) int new;
306: {
307: static int style = 0; /* initial style == upright */
308: static int weight = 0; /* initial weight == medium */
309: static int under = 0; /* initial underline state == off */
310: register int newstyle, newweight, newunder;
311:
312: if (font == new)
313: return; /* unchanged */
314: font = new;
315: newstyle = newweight = newunder = 0; /* defaults */
316: switch(font) {
317: case ROMAN_F:
318: break; /* upright medium */
319: case BOLD_F:
320: newweight = 1; /* bold */
321: break;
322: case ITALIC_F:
323: if (cartridge && !landscape) {
324: newstyle = 1; /* italic */
325: newweight = -1; /* weight -1 */
326: } else
327: newunder = 1; /* underlined upright medium */
328: break;
329: default:
330: fatal("unrecognized font type %d", font);
331: break;
332: }
333: if (under != newunder) {
334: under = newunder;
335: fprintf(output, (under) ? UNDERON : UNDEROFF);
336: }
337: if (style != newstyle && weight != newweight) {
338: style = newstyle;
339: weight = newweight;
340: fprintf(output, STYLEWEIGHT, style, weight);
341: } else if (style != newstyle) {
342: style = newstyle;
343: fprintf(output, STYLE, style);
344: } else if (weight != newweight) {
345: weight = newweight;
346: fprintf(output, STROKEWEIGHT, weight);
347: }
348: }
349:
350: /*
351: * Return 1 if line s is not blank.
352: */
353: int
354: nonblank(s) register char *s;
355: {
356: register int c;
357:
358: while ((c = *s) == ' ' || c == '\t')
359: s++;
360: return (c != '\0' && c != '\n' && c != '\f');
361: }
362:
363: /*
364: * Print a file.
365: * NULL means stdin.
366: */
367: void
368: printfile(file) char *file;
369: {
370: FILE *fp;
371: register int i;
372: int last, end;
373:
374: if (file == NULL)
375: fp = stdin;
376: else if ((fp = fopen(file, "r")) == NULL)
377: fatal("cannot open file \"%s\"", file);
378:
379: if (font != ROMAN_F)
380: newfont(ROMAN_F);
381: for (end = 0; !end; ) {
382: if (rflag) {
383: if (npages >= NPAGES)
384: fatal("more than %d pages", NPAGES);
385: pageaddr[npages++] = ftell(output);
386: }
387: for (i = 0; i < NLINES; i++) {
388: if (fgets(&page[i][0], LINESZ, fp) == NULL) {
389: if (i == 0) {
390: npages--; /* last page empty */
391: return;
392: }
393: end = 1;
394: break;
395: } else if (hasFF(page[i])) { /* formfeed seen */
396: ++i;
397: break;
398: }
399: }
400: for (last = --i; last >= 0; --last)
401: if (nonblank(page[last]))
402: break; /* nonblank line */
403: for (i = 0; i <= last; i++)
404: printline(page[i]);
405: putc('\r', output);
406: if (last < NLINES - 1)
407: putc('\f', output);
408: }
409: if (file != NULL)
410: fclose(fp);
411: }
412:
413: /*
414: * Print one line, substituting special characters from the HP character set.
415: */
416: void
417: printline(cp) register char *cp;
418: {
419: register int c1, c2, new;
420: char *s;
421:
422: /* Replace accents with equivalents from the extended character set. */
423: for (s = cp; *s != '\0'; ++s) {
424: if (*s == '\'' && aflag)
425: *s = ACCENTACUTE;
426: else if (*s == '`')
427: *s = ACCENTGRAVE;
428: }
429:
430: /* Look for nroff font sequences. */
431: while ((c1 = *cp++) != '\0') {
432:
433: /* Check for the interrupt signal. */
434: if (quit)
435: done(2);
436:
437: /* By default, Roman c1 gets printed at the end of this loop. */
438: new = ROMAN_F;
439: if (c1 == '\f')
440: return; /* chars after FF on line get eaten */
441: else if (c1 == ' ' || c1 == '\t')
442: new = font; /* no font change on whitespace */
443: else if (c1 == '_') {
444: if ((c2 = *cp++) == '\b') {
445: /* "_\bx" means italic x. */
446: new = ITALIC_F;
447: c1 = *cp++;
448: } else
449: cp--; /* put back c2 */
450: } else if ((c2 = *cp++) == '\b') {
451: if ((c2 = *cp++) == c1) {
452: /* "x\bx" means bold x. */
453: if (!cartridge || landscape) {
454: fakebold(c1); /* fake it */
455: continue;
456: } else
457: new = BOLD_F;
458: } else
459: cp -= 2; /* put back '\b' and c2 */
460: } else
461: cp--; /* put back c2 */
462: if (font != new)
463: newfont(new); /* font change */
464: putc(c1, output); /* print c1 in new font */
465: }
466: }
467:
468: /*
469: * Copy the temporary file to stdout with the pages in reverse order.
470: */
471: void
472: readback()
473: {
474: char c;
475:
476: while (--npages >= 0) {
477: /* Check for interrupt signal at each page. */
478: if (quit)
479: done(2);
480: fseek(output, pageaddr[npages], 0);
481: while ((c = getc(output)) != '\f')
482: putchar(c);
483: putchar(c);
484: }
485: }
486:
487: /*
488: * Set quit flag when interrupt signal is received.
489: */
490: void
491: trap()
492: {
493: quit = 1;
494: }
495:
496: /*
497: * Print a usage message and die.
498: */
499: void
500: usage()
501: {
502: fprintf(stderr, "%s\n", USAGEMSG);
503: exit(1);
504: }
505:
506: /* end of hp.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.