|
|
1.1 root 1: /*
2: * readPCL.c
3: * 5/20/93
4: *
5: * Usage: readPCL [ -n ] [ infile [ outfile ]]
6: * Option:
7: * -n Produce nroff font info in output;
8: * e.g. "troff foo.r | readPCL -n | nroff -x | more"
9: * Exit status:
10: * 0 success
11: * 1 unrecognized escape sequences seen
12: * 2 fatal error, e.g. file not found
13: * Requires floating point output: cc readPCL.c -f
14: *
15: * Expand PCL commands into readable text.
16: * This currently handles a very small subset of PCL-5,
17: * including only commands which the troff PCL output writer
18: * and /bin/hp write.
19: * Reference: HP "LaserJet III Technical Reference Manual", App. B.
20: */
21:
22: #if __STDC__
23: #define __(args) args
24: #else
25: #define __(args) ()
26: #endif
27:
28: #include <stdio.h>
29: #include <ctype.h>
30:
31: #define VERSION "1.4"
32: #define ESC '\033'
33: #define NVALUE 80 /* max parameter value length */
34:
35: /*
36: * Parameterized commands.
37: * Very small subset of those available.
38: * PVCMD command format depends on parameter value,
39: * PCMD command format does not;
40: * the PVCMD list gets searched first.
41: */
42: typedef struct pvcmd {
43: char pv_char;
44: char pv_group;
45: int pv_value;
46: char pv_param;
47: char *pv_fmt;
48: } PVCMD;
49: typedef struct pcmd {
50: char p_char;
51: char p_group;
52: char p_param;
53: char *p_fmt;
54: } PCMD;
55:
56: /* Parameterized commands with fixed values. */
57: PVCMD pvcmds[] = {
58: { '(', 's', 0, 'p', "fixed" },
59: { '(', 's', 1, 'p', "proportional" },
60: { '(', 's', 0, 's', "upright" },
61: { '(', 's', 1, 's', "italic" },
62: { '&', 'd', 0, 'd', "underline" },
63: { '&', 'd', 3, 'd', "fl underline" },
64: { '&', 'l', 0, 'o', "portrait" },
65: { '&', 'l', 1, 'o', "landscape" },
66: { '&', 'l', 2, 'o', "reverse portrait" },
67: { '&', 'l', 3, 'o', "reverse landscape" },
68: { '&', 'l', 0, 'h', "page eject" }
69: };
70: #define NPVCMDS (sizeof(pvcmds) / sizeof(pvcmds[0]))
71:
72: /* Parameterized commands with arbitrary values; format expects double arg. */
73: PCMD pcmds[] = {
74: { '&', 'a', 'c', "hcol=%g" },
75: { '&', 'a', 'h', "h=%g" },
76: { '&', 'a', 'l', "left margin=%g" },
77: { '&', 'a', 'v', "v=%g" },
78: { '&', 'd', '@'+32, "underline off" },
79: { '&', 'l', 'd', "line spacing=%g" },
80: { '&', 'l', 'e', "top margin=%g" },
81: { '&', 'l', 'f', "text length=%g" },
82: { '&', 'l', 'p', "page length=%g" },
83: { '(', '0', 'u', "symset=ASCII" },
84: { '(', 's', 'b', "weight=%g" },
85: { '(', 's', 'h', "pitch=%g" },
86: { '(', 's', 't', "typeface=%g" },
87: { '(', 's', 'v', "pointsize=%g" }
88: };
89: #define NPCMDS (sizeof(pcmds) / sizeof(pcmds[0]))
90:
91: /*
92: * Two-character commands.
93: * Small subset of those available.
94: */
95: typedef struct tcmd {
96: char t_char;
97: char *t_fmt;
98: } TCMD;
99: TCMD tcmds[] = {
100: { '9', "clear" },
101: { 'E', "reset" }
102: };
103: #define NTCMDS (sizeof(tcmds) / sizeof(tcmds[0]))
104:
105: /* External. */
106: extern double atof();
107:
108: /* Forward. */
109: extern void error __((char *fmt, ... ));
110: extern void escape __((void ));
111: extern void esc_param __((int c ));
112: extern void esc_two __((int c ));
113: extern void fatal __((char *fmt, ... ));
114: extern void lookup __((int c, int group, double val, int param));
115: extern FILE *openfile __((char *name, char *mode ));
116: extern void usage __((void ));
117: extern double value __((int *signp ));
118:
119: /* Globals. */
120: int nflag; /* nroff output */
121: int status; /* exit status */
122: FILE *ifp = stdin; /* input FILE */
123: FILE *ofp = stdout; /* output FILE */
124:
125: int
126: main(argc, argv) int argc; char *argv[];
127: {
128: register char *s;
129: register int c;
130:
131: /* Look for options. */
132: if (argc > 1 && argv[1][0] == '-') {
133: for (s = &argv[1][1]; *s != '\0'; s++) {
134: switch(*s) {
135: case 'n': ++nflag; break;
136: case 'V':
137: fprintf(stderr, "readPCL: V" VERSION "\n");
138: break;
139: default: usage(); break;
140: }
141: }
142: --argc;
143: ++argv;
144: }
145:
146: /* Open files. */
147: if (argc > 1)
148: ifp = openfile(argv[1], "rb");
149: if (argc > 2)
150: ofp = openfile(argv[2], "w");
151:
152: /* Process. */
153: if (nflag)
154: fprintf(ofp, ".nf\n");
155: while ((c = getc(ifp)) != EOF) {
156: if (c == ESC)
157: escape();
158: else
159: putc(c, ofp);
160: }
161:
162: /* Done. */
163: if (ifp != stdin)
164: fclose(ifp);
165: if (ofp != stdout)
166: fclose(ofp);
167: exit(status);
168: }
169:
170: /*
171: * Print an unrecognized escape sequence to the output text
172: * and an error message to stderr.
173: * Bump the error count.
174: */
175: /* VARARGS */
176: void
177: error(fmt) char *fmt;
178: {
179: status = 1;
180: fprintf(ofp, "ESC %r", &fmt);
181: fprintf(stderr, "readPCL: unrecognized ESC sequence: ESC %r\n", &fmt);
182: }
183:
184: /*
185: * Handle an escape sequence.
186: */
187: void
188: escape()
189: {
190: register int c;
191:
192: putc('\n', ofp);
193: if (nflag)
194: fprintf(ofp, "\\fB");
195: putc('{', ofp);
196: if ((c = getc(ifp)) >= 33 && c <= 47)
197: esc_param(c); /* parameterized */
198: else if (c >= 48 && c <= 126)
199: esc_two(c); /* two-character */
200: else
201: error("%c (0x%X)", c, c);
202: putc('}', ofp);
203: if (nflag)
204: fprintf(ofp, "\\fP");
205: }
206:
207: /*
208: * Parameterized escape sequence starting with c.
209: */
210: void
211: esc_param(c) register int c;
212: {
213: int group, param, done, sign;
214: double val;
215:
216: group = getc(ifp);
217: for (done = 0; !done; ) {
218: val = value(&sign);
219: param = getc(ifp);
220: if (param >= 64 && param <= 94) {
221: ++done;
222: param += 32;
223: }
224: if (sign)
225: fprintf(ofp, "relative ");
226: lookup(c, group, val, param);
227: if (!done)
228: putc(';', ofp);
229: }
230: }
231:
232: /*
233: * Two-character escape sequence starting with c.
234: */
235: void
236: esc_two(c) register int c;
237: {
238: register TCMD *p;
239:
240: for (p = tcmds; p < &tcmds[NPCMDS]; p++) {
241: if (c == p->t_char) {
242: fprintf(ofp, p->t_fmt);
243: return;
244: }
245: }
246: error("%c (0x%X)", c, c);
247: }
248:
249: /*
250: * Print a fatal error message and die.
251: */
252: /* VARARGS */
253: void
254: fatal(fmt) char *fmt;
255: {
256: fprintf(stderr, "readPCL: %r\n", &fmt);
257: exit(2);
258: }
259:
260: /*
261: * Look up a parameterized command.
262: * Print either a formatted message or an error message.
263: */
264: void
265: lookup(c, group, val, param) int c, group; double val; int param;
266: {
267: register PVCMD *pvp;
268: register PCMD *pcp;
269:
270: /* Look for commands with matching value first. */
271: for (pvp = pvcmds; pvp < &pvcmds[NPVCMDS]; pvp++) {
272: if (c == pvp->pv_char
273: && group == pvp->pv_group
274: && (int)val == pvp->pv_value
275: && param == pvp->pv_param) {
276: fprintf(ofp, pvp->pv_fmt);
277: return;
278: }
279: }
280:
281: /* Then look for commands with arbitrary value. */
282: for (pcp = pcmds; pcp < &pcmds[NPCMDS]; pcp++) {
283: if (c == pcp->p_char
284: && group == pcp->p_group
285: && param == pcp->p_param) {
286: fprintf(ofp, pcp->p_fmt, val);
287: return;
288: }
289: }
290:
291: /* Not found. */
292: error("%c %c %g %c", c, group, val, param);
293: }
294:
295: /*
296: * Open a FILE.
297: */
298: FILE *
299: openfile (name, mode) char *name; char *mode;
300: {
301: register FILE *fp;
302:
303: if ((fp = fopen(name, mode)) == NULL)
304: fatal("cannot open file \"%s\"", name);
305: return fp;
306: }
307:
308: /*
309: * Print a usage message and die.
310: */
311: void
312: usage()
313: {
314: fprintf(stderr,
315: "Usage: readPCL [ -n ] [ infile [ outfile ]]\n"
316: "Option:\n"
317: "\t-n\tProduce nroff output;\n"
318: "\t\te.g. \"troff foo.r | readPCL -n | nroff -x | more\"\n"
319: );
320: exit(1);
321: }
322:
323: /*
324: * Read a PCL value field:
325: * ASCII number consisting of optional sign, digits and optional decimal point.
326: * Store the sign through *signp: -1 for '-', 0 for none, 1 for '+';
327: * for some PCL commands, the value can be absolute or relative,
328: * depending on the presence/absence of the sign.
329: * Return 0.0 if the value is missing.
330: */
331: double
332: value(signp) int *signp;
333: {
334: char buf[NVALUE];
335: register char *cp;
336: register int c, s, dotseen;
337: double d;
338:
339: /* Handle optional sign. */
340: dotseen = s = 0;
341: if ((c = getc(ifp)) == '-')
342: --s;
343: else if (c == '+')
344: ++s;
345: else
346: ungetc(c, ifp);
347:
348: /* Read the number into buf[]. */
349: for (cp = buf; isdigit(c = getc(ifp)) || (c=='.' && (dotseen++ == 0)); )
350: *cp++ = c;
351: *cp = '\0';
352: ungetc(c, ifp);
353:
354: /* Return converted value; note that atof("") returns 0.0. */
355: d = atof(buf);
356: *signp = s;
357: return (s == -1) ? -d : d;
358: }
359:
360: /* end of readPCL.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.