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