1 /******************************************************************************
2 File: $Id: pclscan.c,v 1.8 2000-10-22 11:05:34+02 Martin Rel $
3 Contents: PCL scanner
4 Author: Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig,
5 Germany, e-mail: Martin.Lottermoser@t-online.de
6
7 *******************************************************************************
8 * *
9 * Copyright (C) 1999, 2000 by Martin Lottermoser *
10 * All rights reserved *
11 * *
12 ******************************************************************************/
13
14 /* Configuration management identification */
15 #ifndef lint
16 static const char
17 cm_id[] = "@(#)$Id: pclscan.c,v 1.8 2000-10-22 11:05:34+02 Martin Rel $";
18 #endif
19
20 /*****************************************************************************/
21
22 #ifndef _XOPEN_SOURCE
23 #define _XOPEN_SOURCE 500
24 #endif
25 #ifndef _XOPEN_SOURCE_EXTENDED
26 #define _XOPEN_SOURCE_EXTENDED 1
27 #endif
28
29 /* Standard headers */
30 #include <errno.h>
31 #include <nl_types.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 /* Special headers */
37 #include "pclscan.h"
38
39 /*****************************************************************************/
40
41 static nl_catd catd = (nl_catd)-1; /* NLS catalogue descriptor */
42
43
message(int id,const char * s)44 static void message(int id, const char *s)
45 {
46 if (catd != (nl_catd)-1) s = catgets(catd, 1, id, s);
47 /* The check might not be necessary (X/Open requires catgets() to return 's'
48 if the call is unsuccessful for *any* reason and the possible errors
49 include EBADF for an invalid 'catd'), but one never knows. */
50
51 fputs("? pclscan: ", stderr);
52 fprintf(stderr, s);
53 fputc('\n', stderr);
54
55 return;
56 }
57
58 /*****************************************************************************/
59
60 static const pcl_Octet ESC = '\x1B';
61
62 /******************************************************************************
63
64 Function: pcl_is_control_code
65
66 This function returns a non-zero value iff 'c', taken to be an unsigned char
67 converted to 'int', is a PCL control code.
68
69 ******************************************************************************/
70
pcl_is_control_code(int c)71 int pcl_is_control_code(int c)
72 {
73 return
74 c <= ' ' && (
75 c == '\0' ||
76 /* TRG500 does not mention NUL as a control code. */
77 c == '\b' || c == '\t' || c == '\n' || c == '\f' || c == '\r' ||
78 c == '\x0E' /* Shift Out (SO) */ ||
79 c == '\x0F' /* Shift In (SI) */ ||
80 c == '\x11' /* Device Control 1 (DC1) */ ||
81 c == '\x13' /* Device Control 3 (DC3) */ ||
82 c == ESC ||
83 c == ' ');
84 }
85
86 /*****************************************************************************/
87
cmp_strings(const void * a,const void * b)88 static int cmp_strings(const void *a, const void *b)
89 {
90 return strncmp((const char *)a, (const char *)b, 3);
91 }
92
93
default_interpreter(FILE * in,const pcl_Command * cmd)94 static int default_interpreter(FILE *in, const pcl_Command *cmd)
95 {
96 /* Skip over arguments for those commands which are known to have them */
97 if (cmd->kind >= 3) {
98 if (strncmp((const char *)cmd->chars, "%-X", 3) == 0 && cmd->i == 12345) {
99 /* Universal Exit Language (UEL)/Start of PJL */
100 int c;
101
102 do {
103 c = fgetc(in);
104 if (c != '@') break;
105 do c = fgetc(in); while (c != EOF && c != '\n');
106 } while (c != EOF);
107 if (c != EOF) ungetc(c, in);
108 }
109 else if (cmd->i > 0) {
110 static const char with_args[][4] = {
111 /* Must be sorted with respect to cmp_strings() */
112 "&bW",
113 "&iW",
114 "&pX", /* Transparent Print Mode */
115 "(sW", /* Download Character */
116 ")sW", /* Create Font */
117 "*bV", /* Transfer Raster Graphics Data by Plane */
118 "*bW", /* Transfer Raster Graphics Data by Row */
119 "*dW", /* Palette Configuration */
120 "*gW", /* Configure Raster Data */
121 "*oW"};
122
123 if (bsearch(cmd->chars, with_args,
124 sizeof(with_args)/sizeof(with_args[0]), sizeof(with_args[0]),
125 &cmp_strings) != NULL) {
126 int j;
127
128 j = cmd->i;
129 while (j > 0 && fgetc(in) != EOF) j--;
130 if (j > 0) {
131 message(1, "Premature EOF on input.");
132 return -1;
133 }
134 }
135 }
136 }
137 else if (cmd->kind == 2 && cmd->chars[0] == 'Y') {
138 /* Display Functions Mode ON */
139 int c;
140
141 /* Read until EOF or Display Functions Mode OFF */
142 do {
143 do c = fgetc(in); while (c != EOF && c != ESC);
144 if (c != EOF) c = fgetc(in);
145 } while (c != EOF && c != 'Z');
146
147 if (c != 'Z') {
148 message(1, "Premature EOF on input.");
149 return -1;
150 }
151 }
152
153 return 0;
154 }
155
156 /*****************************************************************************/
157
default_handler(FILE * in)158 static int default_handler(FILE *in)
159 {
160 int c;
161
162 do {
163 c = fgetc(in);
164 } while (c != EOF && !pcl_is_control_code(c));
165 if (c != EOF) ungetc(c, in);
166
167 return 0;
168 }
169
170 /******************************************************************************
171
172 Function: pcl_scan
173
174 This function scans a PCL file, separating it into printer commands and
175 unknown data, and calling the functions '(*interpreter)()' and '(*handler)()'
176 with these parts, respectively.
177
178 'in' must have been opened as a binary file and for reading.
179 'interpreter' or 'handler' may be null in which case default routines are
180 used.
181 If a non-NULL function pointer is provided for 'interpreter' or 'handler',
182 the function will be passed the value of 'idata' or 'hdata', respectively.
183
184 This function returns zero on success and a negative value otherwise.
185 If one of the interpreter or data handler functions returns a negative value,
186 processing will stop and the value will be returned as the return value of
187 pcl_scan().
188
189 ******************************************************************************/
190
pcl_scan(FILE * in,pcl_CommandInterpreter interpreter,void * idata,pcl_UnknownDataHandler handler,void * hdata)191 int pcl_scan(FILE *in, pcl_CommandInterpreter interpreter, void *idata,
192 pcl_UnknownDataHandler handler, void *hdata)
193 {
194 int
195 c,
196 rc = 0;
197
198 /* Open catalogue descriptor */
199 catd = catopen("pcltools", 0);
200 if (catd == (nl_catd)(-1) && errno != ENOENT)
201 /* A system returning ENOENT if no catalogue is available is for example
202 Sun Solaris 2.5. */
203 fprintf(stderr,
204 "?-W pclscan: Error trying to open message catalogue: %s.\n",
205 strerror(errno));
206
207 /* Loop over input */
208 while (rc >= 0 && (c = fgetc(in)) != EOF) {
209 if (c == ESC) {
210 pcl_Command command;
211
212 if ((c = fgetc(in)) == EOF) {
213 rc = -1;
214 message(1, "Premature EOF on input.");
215 break;
216 }
217 command.chars[0] = c;
218 if (48 <= c && c <= 126) {
219 /* Two-character escape sequence */
220 command.kind = 2;
221 if (interpreter == NULL ||
222 (rc = (*interpreter)(in, &command, idata)) > 0)
223 rc = default_interpreter(in, &command);
224 }
225 else {
226 int continued;
227
228 /* Parameterized escape sequence or garbage. The character we've just
229 read is the "parameterized character" and it should be in the range
230 33-47. */
231
232 /* Now the group character (should be in the range 96-126, but HP uses
233 sometimes at least '-', which has the value 45) */
234 if ((c = fgetc(in)) == EOF) {
235 rc = -1;
236 message(1, "Premature EOF on input.");
237 break;
238 }
239 command.chars[1] = c;
240
241 continued = 0;
242 do {
243 /* Now for the value */
244 if ((c = fgetc(in)) == EOF) {
245 rc = -1;
246 message(1, "Premature EOF on input.");
247 break;
248 }
249 if (c == '+' || c == '-' || '0' <= c && c <= '9') {
250 if (c == '+' || c == '-') command.prefix = c;
251 else command.prefix = ' ';
252 ungetc(c, in);
253 if (fscanf(in, "%d", &command.i) != 1) {
254 rc = -1;
255 message(2, "Syntax error in value field.");
256 break;
257 }
258
259 /* Decimal point? */
260 if ((c = fgetc(in)) == EOF) {
261 rc = -1;
262 message(1, "Premature EOF on input.");
263 break;
264 }
265 command.scale = 0;
266 command.fraction = 0;
267 if (c == '.') {
268 command.scale = 1;
269 while ((c = fgetc(in)) != EOF && '0' <= c && c <= '9') {
270 command.fraction = command.fraction*10 + (c - '0');
271 command.scale *= 10;
272 }
273 if (c == EOF) {
274 rc = -1;
275 message(1, "Premature EOF on input.");
276 break;
277 }
278 if (command.prefix == '-') command.fraction = -command.fraction;
279 }
280 }
281 else {
282 command.prefix = '\0'; /* no value given */
283 command.i = 0;
284 }
285
286 /* Final character */
287 if (96 <= c && c <= 126) {
288 /* Parameter character */
289 command.chars[2] = c - ('a' - 'A');
290 command.kind = (continued? 6: 4);
291 continued = 1;
292 }
293 else {
294 /* Termination character (should be in the range 64-94) */
295 command.chars[2] = c;
296 command.kind = (continued? 5: 3);
297 continued = 0;
298 }
299
300 if (interpreter == NULL ||
301 (rc = (*interpreter)(in, &command, idata)) > 0)
302 rc = default_interpreter(in, &command);
303 } while (rc == 0 && continued);
304 }
305 }
306 else if (pcl_is_control_code(c)) {
307 pcl_Command command;
308
309 command.chars[0] = c;
310 command.kind = 1;
311 command.i = 1; /* number of occurrences */
312
313 while ((c = fgetc(in)) != EOF && c == command.chars[0]) command.i++;
314 if (c != EOF) ungetc(c, in);
315
316 if (interpreter == NULL ||
317 (rc = (*interpreter)(in, &command, idata)) > 0)
318 rc = default_interpreter(in, &command);
319 }
320 else {
321 ungetc(c, in);
322 if (handler == NULL || (rc = (*handler)(in, hdata)) > 0)
323 rc = default_handler(in);
324 }
325 }
326
327 /* Close catalogue descriptor */
328 if (catd != (nl_catd)-1) catclose(catd);
329
330 return rc;
331 }
332