]>
Commit | Line | Data |
---|---|---|
80ca4592 | 1 | /* |
503b54c9 | 2 | * DSC test program for CUPS. |
80ca4592 | 3 | * |
503b54c9 MS |
4 | * Copyright 2007-2010 by Apple Inc. |
5 | * Copyright 2006 by Easy Software Products, all rights reserved. | |
80ca4592 | 6 | * |
e3101897 | 7 | * Licensed under Apache License v2.0. See the file "LICENSE" for more information. |
80ca4592 | 8 | * |
503b54c9 | 9 | * PostScript is a trademark of Adobe Systems, Inc. |
80ca4592 | 10 | */ |
11 | ||
12 | /* | |
13 | * Include necessary headers... | |
14 | */ | |
15 | ||
71e16022 | 16 | #include <cups/cups-private.h> |
80ca4592 | 17 | |
18 | ||
19 | /* | |
20 | * Local functions... | |
21 | */ | |
22 | ||
23 | static int check_file(const char *filename); | |
85dda01c | 24 | static void usage(void) __attribute__((noreturn)); |
80ca4592 | 25 | |
26 | ||
27 | /* | |
28 | * 'main()' - Main entry for test program. | |
29 | */ | |
30 | ||
31 | int /* O - Exit status */ | |
32 | main(int argc, /* I - Number of command-line args */ | |
33 | char *argv[]) /* I - Command-line arguments */ | |
34 | { | |
35 | int i; /* Looping var */ | |
36 | int status; /* Status of tests */ | |
37 | int num_files; /* Number of files tested */ | |
38 | ||
39 | ||
07725fee | 40 | _cupsSetLocale(argv); |
d09495fa | 41 | |
80ca4592 | 42 | /* |
43 | * Collect command-line arguments... | |
44 | */ | |
45 | ||
46 | for (i = 1, num_files = 0, status = 0; i < argc; i ++) | |
47 | if (argv[i][0] == '-') | |
48 | { | |
49 | if (argv[i][1]) | |
50 | { | |
51 | /* | |
52 | * Currently the only supported option is "-h" (help)... | |
53 | */ | |
54 | ||
55 | usage(); | |
56 | } | |
57 | else | |
58 | { | |
59 | num_files ++; | |
60 | status += check_file("(stdin)"); | |
61 | } | |
62 | } | |
63 | else | |
64 | { | |
65 | num_files ++; | |
66 | status += check_file(argv[i]); | |
67 | } | |
68 | ||
69 | if (!num_files) | |
70 | usage(); | |
71 | ||
72 | return (status); | |
73 | } | |
74 | ||
75 | ||
76 | /* | |
89d46774 | 77 | * 'check()' - Check a file for conformance. |
80ca4592 | 78 | */ |
79 | ||
80 | static int /* O - 0 on success, 1 on failure */ | |
81 | check_file(const char *filename) /* I - File to read from */ | |
82 | { | |
83 | int i; /* Looping var */ | |
84 | cups_file_t *fp; /* File */ | |
85 | char line[1024]; /* Line from file */ | |
86 | int ch; /* Current character */ | |
87 | size_t bytes; /* Length of line */ | |
88 | int status; /* Status of test */ | |
89 | int linenum; /* Line number */ | |
90 | int binary; /* File contains binary data? */ | |
91 | float version; /* DSC version */ | |
92 | int lbrt[4]; /* Bounding box */ | |
93 | char page_label[256]; /* Page label string */ | |
94 | int page_number; /* Page number */ | |
89d46774 | 95 | int last_page_number; /* Last page number seen */ |
80ca4592 | 96 | int level; /* Embedded document level */ |
97 | int saw_bounding_box, /* %%BoundingBox seen? */ | |
98 | saw_pages, /* %%Pages seen? */ | |
99 | saw_end_comments, /* %%EndComments seen? */ | |
100 | saw_begin_prolog, /* %%BeginProlog seen? */ | |
101 | saw_end_prolog, /* %%EndProlog seen? */ | |
102 | saw_begin_setup, /* %%BeginSetup seen? */ | |
103 | saw_end_setup, /* %%EndSetup seen? */ | |
104 | saw_page, /* %%Page seen? */ | |
105 | saw_trailer, /* %%Trailer seen? */ | |
80ca4592 | 106 | saw_long_line; /* Saw long lines? */ |
107 | ||
108 | ||
109 | /* | |
110 | * Open the file... | |
111 | */ | |
112 | ||
113 | if (!strcmp(filename, "(stdin)")) | |
114 | fp = cupsFileStdin(); | |
115 | else | |
116 | fp = cupsFileOpen(filename, "r"); | |
117 | ||
118 | if (!fp) | |
119 | { | |
120 | perror(filename); | |
121 | return (1); | |
122 | } | |
123 | ||
124 | /* | |
125 | * Scan the file... | |
126 | */ | |
127 | ||
128 | binary = 0; | |
89d46774 | 129 | last_page_number = 0; |
80ca4592 | 130 | level = 0; |
131 | linenum = 0; | |
132 | saw_begin_prolog = 0; | |
133 | saw_begin_setup = 0; | |
134 | saw_bounding_box = 0; | |
135 | saw_end_comments = 0; | |
136 | saw_end_prolog = 0; | |
137 | saw_end_setup = 0; | |
80ca4592 | 138 | saw_long_line = 0; |
139 | saw_page = 0; | |
140 | saw_pages = 0; | |
141 | saw_trailer = 0; | |
142 | status = 0; | |
143 | version = 0.0f; | |
144 | ||
0837b7e8 MS |
145 | /* TODO: Fixme */ |
146 | printf("%s: ", filename); | |
80ca4592 | 147 | fflush(stdout); |
148 | ||
149 | while ((bytes = cupsFileGetLine(fp, line, sizeof(line))) > 0) | |
150 | { | |
151 | linenum ++; | |
152 | ||
153 | if (bytes > 255) | |
154 | { | |
155 | if (!saw_long_line) | |
156 | { | |
157 | if (!status) | |
0837b7e8 | 158 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 159 | |
160 | status ++; | |
161 | _cupsLangPrintf(stdout, | |
0837b7e8 MS |
162 | _(" Line %d is longer than 255 characters (%d).\n" |
163 | " REF: Page 25, Line Length"), | |
80ca4592 | 164 | linenum, (int)bytes); |
165 | } | |
166 | ||
167 | saw_long_line ++; | |
168 | } | |
169 | ||
170 | if (linenum == 1) | |
171 | { | |
172 | if (strncmp(line, "%!PS-Adobe-", 11)) | |
173 | { | |
174 | if (!status) | |
0837b7e8 | 175 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 176 | |
80ca4592 | 177 | _cupsLangPuts(stdout, |
0837b7e8 MS |
178 | _(" Missing %!PS-Adobe-3.0 on first line.\n" |
179 | " REF: Page 17, 3.1 Conforming Documents")); | |
80ca4592 | 180 | cupsFileClose(fp); |
181 | return (1); | |
182 | } | |
183 | else | |
68c4690a | 184 | version = (float)atof(line + 11); |
80ca4592 | 185 | } |
186 | else if (level > 0) | |
187 | { | |
188 | if (!strncmp(line, "%%BeginDocument:", 16)) | |
189 | level ++; | |
190 | else if (!strncmp(line, "%%EndDocument", 13)) | |
191 | level --; | |
192 | } | |
193 | else if (saw_trailer) | |
194 | { | |
195 | if (!strncmp(line, "%%Pages:", 8)) | |
196 | { | |
197 | if (atoi(line + 8) <= 0) | |
198 | { | |
199 | if (!status) | |
0837b7e8 | 200 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 201 | |
202 | status ++; | |
203 | _cupsLangPrintf(stdout, | |
0837b7e8 MS |
204 | _(" Bad %%%%Pages: on line %d.\n" |
205 | " REF: Page 43, %%%%Pages:"), | |
80ca4592 | 206 | linenum); |
207 | } | |
208 | else | |
209 | saw_pages = 1; | |
210 | } | |
211 | else if (!strncmp(line, "%%BoundingBox:", 14)) | |
212 | { | |
213 | if (sscanf(line + 14, "%d%d%d%d", lbrt + 0, lbrt + 1, lbrt + 2, | |
214 | lbrt + 3) != 4) | |
215 | { | |
216 | if (!status) | |
0837b7e8 | 217 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 218 | |
219 | status ++; | |
0837b7e8 MS |
220 | _cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n" |
221 | " REF: Page 39, %%%%BoundingBox:"), | |
80ca4592 | 222 | linenum); |
223 | } | |
224 | else | |
225 | saw_bounding_box = 1; | |
226 | } | |
227 | } | |
228 | else if (!saw_end_comments) | |
229 | { | |
230 | if (!strncmp(line, "%%EndComments", 13)) | |
231 | saw_end_comments = 1; | |
232 | else if (line[0] != '%') | |
233 | saw_end_comments = -1; | |
234 | else if (!strncmp(line, "%%Pages:", 8)) | |
235 | { | |
236 | if (strstr(line + 8, "(atend)")) | |
237 | saw_pages = -1; | |
238 | else if (atoi(line + 8) <= 0) | |
239 | { | |
240 | if (!status) | |
0837b7e8 | 241 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 242 | |
243 | status ++; | |
0837b7e8 MS |
244 | _cupsLangPrintf(stdout, _(" Bad %%%%Pages: on line %d.\n" |
245 | " REF: Page 43, %%%%Pages:"), | |
80ca4592 | 246 | linenum); |
247 | } | |
248 | else | |
249 | saw_pages = 1; | |
250 | } | |
251 | else if (!strncmp(line, "%%BoundingBox:", 14)) | |
252 | { | |
253 | if (strstr(line, "(atend)")) | |
254 | saw_bounding_box = -1; | |
255 | else if (sscanf(line + 14, "%d%d%d%d", lbrt + 0, lbrt + 1, lbrt + 2, | |
256 | lbrt + 3) != 4) | |
257 | { | |
258 | if (!status) | |
0837b7e8 | 259 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 260 | |
261 | status ++; | |
0837b7e8 MS |
262 | _cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n" |
263 | " REF: Page 39, %%%%BoundingBox:"), | |
80ca4592 | 264 | linenum); |
265 | } | |
266 | else | |
267 | saw_bounding_box = 1; | |
268 | } | |
269 | } | |
270 | else if (saw_begin_prolog && !saw_end_prolog) | |
271 | { | |
272 | if (!strncmp(line, "%%EndProlog", 11)) | |
273 | saw_end_prolog = 1; | |
274 | } | |
275 | else if (saw_begin_setup && !saw_end_setup) | |
276 | { | |
277 | if (!strncmp(line, "%%EndSetup", 10)) | |
278 | saw_end_setup = 1; | |
279 | } | |
280 | else if (saw_end_comments) | |
281 | { | |
282 | if (!strncmp(line, "%%Page:", 7)) | |
283 | { | |
89d46774 | 284 | if (sscanf(line + 7, "%255s%d", page_label, &page_number) != 2 || |
285 | page_number != (last_page_number + 1) || page_number < 1) | |
80ca4592 | 286 | { |
287 | if (!status) | |
0837b7e8 | 288 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 289 | |
290 | status ++; | |
0837b7e8 MS |
291 | _cupsLangPrintf(stdout, _(" Bad %%%%Page: on line %d.\n" |
292 | " REF: Page 53, %%%%Page:"), | |
80ca4592 | 293 | linenum); |
294 | } | |
295 | else | |
89d46774 | 296 | { |
297 | last_page_number = page_number; | |
298 | saw_page = 1; | |
299 | } | |
80ca4592 | 300 | } |
301 | else if (!strncmp(line, "%%BeginProlog", 13)) | |
302 | saw_begin_prolog = 1; | |
303 | else if (!strncmp(line, "%%BeginSetup", 12)) | |
304 | saw_begin_setup = 1; | |
305 | else if (!strncmp(line, "%%BeginDocument:", 16)) | |
306 | level ++; | |
307 | else if (!strncmp(line, "%%EndDocument", 13)) | |
308 | level --; | |
309 | else if (!strncmp(line, "%%Trailer", 9)) | |
310 | saw_trailer = 1; | |
311 | } | |
312 | ||
68c4690a | 313 | for (i = 0; !binary && i < (int)bytes; i ++) |
80ca4592 | 314 | { |
315 | ch = line[i]; | |
316 | ||
317 | if ((ch < ' ' || (ch & 0x80)) && ch != '\n' && ch != '\r' && ch != '\t') | |
318 | binary = 1; | |
319 | } | |
320 | } | |
321 | ||
322 | if (saw_bounding_box <= 0) | |
323 | { | |
324 | if (!status) | |
0837b7e8 | 325 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 326 | |
327 | status ++; | |
0837b7e8 MS |
328 | _cupsLangPuts(stdout, _(" Missing or bad %%BoundingBox: comment.\n" |
329 | " REF: Page 39, %%BoundingBox:")); | |
80ca4592 | 330 | } |
331 | ||
332 | if (saw_pages <= 0) | |
333 | { | |
334 | if (!status) | |
0837b7e8 | 335 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 336 | |
337 | status ++; | |
0837b7e8 MS |
338 | _cupsLangPuts(stdout, _(" Missing or bad %%Pages: comment.\n" |
339 | " REF: Page 43, %%Pages:")); | |
80ca4592 | 340 | } |
341 | ||
342 | if (!saw_end_comments) | |
343 | { | |
344 | if (!status) | |
0837b7e8 | 345 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 346 | |
347 | status ++; | |
0837b7e8 MS |
348 | _cupsLangPuts(stdout, _(" Missing %%EndComments comment." |
349 | " REF: Page 41, %%EndComments")); | |
80ca4592 | 350 | } |
351 | ||
352 | if (!saw_page) | |
353 | { | |
354 | if (!status) | |
0837b7e8 | 355 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 356 | |
357 | status ++; | |
0837b7e8 MS |
358 | _cupsLangPuts(stdout, _(" Missing or bad %%Page: comments.\n" |
359 | " REF: Page 53, %%Page:")); | |
80ca4592 | 360 | } |
361 | ||
362 | if (level < 0) | |
363 | { | |
364 | if (!status) | |
0837b7e8 | 365 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 366 | |
367 | status ++; | |
0837b7e8 | 368 | _cupsLangPuts(stdout, _(" Too many %%EndDocument comments.")); |
80ca4592 | 369 | } |
370 | else if (level > 0) | |
371 | { | |
372 | if (!status) | |
0837b7e8 | 373 | _cupsLangPuts(stdout, _("FAIL")); |
80ca4592 | 374 | |
375 | status ++; | |
0837b7e8 | 376 | _cupsLangPuts(stdout, _(" Too many %%BeginDocument comments.")); |
80ca4592 | 377 | } |
378 | ||
379 | if (saw_long_line > 1) | |
380 | _cupsLangPrintf(stderr, | |
0837b7e8 | 381 | _(" Saw %d lines that exceeded 255 characters."), |
80ca4592 | 382 | saw_long_line); |
383 | ||
384 | if (!status) | |
0837b7e8 | 385 | _cupsLangPuts(stdout, _("PASS")); |
80ca4592 | 386 | |
387 | if (binary) | |
0837b7e8 | 388 | _cupsLangPuts(stdout, _(" Warning: file contains binary data.")); |
80ca4592 | 389 | |
390 | if (version < 3.0f) | |
391 | _cupsLangPrintf(stdout, | |
0837b7e8 | 392 | _(" Warning: obsolete DSC version %.1f in file."), |
80ca4592 | 393 | version); |
394 | ||
395 | if (saw_end_comments < 0) | |
0837b7e8 | 396 | _cupsLangPuts(stdout, _(" Warning: no %%EndComments comment in file.")); |
80ca4592 | 397 | |
398 | cupsFileClose(fp); | |
399 | ||
400 | return (status); | |
401 | } | |
402 | ||
403 | ||
404 | /* | |
405 | * 'usage()' - Show program usage. | |
406 | */ | |
407 | ||
408 | static void | |
409 | usage(void) | |
410 | { | |
0837b7e8 MS |
411 | _cupsLangPuts(stdout, _("Usage: cupstestdsc [options] filename.ps [... " |
412 | "filename.ps]")); | |
413 | _cupsLangPuts(stdout, _(" cupstestdsc [options] -")); | |
414 | _cupsLangPuts(stdout, ""); | |
415 | _cupsLangPuts(stdout, _("Options:")); | |
416 | _cupsLangPuts(stdout, ""); | |
417 | _cupsLangPuts(stdout, _(" -h Show program usage")); | |
418 | _cupsLangPuts(stdout, ""); | |
419 | _cupsLangPuts(stdout, _("Note: this program only validates the DSC comments, " | |
420 | "not the PostScript itself.")); | |
421 | ||
80ca4592 | 422 | exit(1); |
423 | } |