]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/cupstestdsc.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / systemv / cupstestdsc.c
1 /*
2 * DSC test program for CUPS.
3 *
4 * Copyright 2007-2010 by Apple Inc.
5 * Copyright 2006 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 *
9 * PostScript is a trademark of Adobe Systems, Inc.
10 */
11
12 /*
13 * Include necessary headers...
14 */
15
16 #include <cups/cups-private.h>
17
18
19 /*
20 * Local functions...
21 */
22
23 static int check_file(const char *filename);
24 static void usage(void) __attribute__((noreturn));
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
40 _cupsSetLocale(argv);
41
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 /*
77 * 'check()' - Check a file for conformance.
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 */
95 int last_page_number; /* Last page number seen */
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? */
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;
129 last_page_number = 0;
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;
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
145 /* TODO: Fixme */
146 printf("%s: ", filename);
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)
158 _cupsLangPuts(stdout, _("FAIL"));
159
160 status ++;
161 _cupsLangPrintf(stdout,
162 _(" Line %d is longer than 255 characters (%d).\n"
163 " REF: Page 25, Line Length"),
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)
175 _cupsLangPuts(stdout, _("FAIL"));
176
177 _cupsLangPuts(stdout,
178 _(" Missing %!PS-Adobe-3.0 on first line.\n"
179 " REF: Page 17, 3.1 Conforming Documents"));
180 cupsFileClose(fp);
181 return (1);
182 }
183 else
184 version = (float)atof(line + 11);
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)
200 _cupsLangPuts(stdout, _("FAIL"));
201
202 status ++;
203 _cupsLangPrintf(stdout,
204 _(" Bad %%%%Pages: on line %d.\n"
205 " REF: Page 43, %%%%Pages:"),
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)
217 _cupsLangPuts(stdout, _("FAIL"));
218
219 status ++;
220 _cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n"
221 " REF: Page 39, %%%%BoundingBox:"),
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)
241 _cupsLangPuts(stdout, _("FAIL"));
242
243 status ++;
244 _cupsLangPrintf(stdout, _(" Bad %%%%Pages: on line %d.\n"
245 " REF: Page 43, %%%%Pages:"),
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)
259 _cupsLangPuts(stdout, _("FAIL"));
260
261 status ++;
262 _cupsLangPrintf(stdout, _(" Bad %%%%BoundingBox: on line %d.\n"
263 " REF: Page 39, %%%%BoundingBox:"),
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 {
284 if (sscanf(line + 7, "%255s%d", page_label, &page_number) != 2 ||
285 page_number != (last_page_number + 1) || page_number < 1)
286 {
287 if (!status)
288 _cupsLangPuts(stdout, _("FAIL"));
289
290 status ++;
291 _cupsLangPrintf(stdout, _(" Bad %%%%Page: on line %d.\n"
292 " REF: Page 53, %%%%Page:"),
293 linenum);
294 }
295 else
296 {
297 last_page_number = page_number;
298 saw_page = 1;
299 }
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
313 for (i = 0; !binary && i < (int)bytes; i ++)
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)
325 _cupsLangPuts(stdout, _("FAIL"));
326
327 status ++;
328 _cupsLangPuts(stdout, _(" Missing or bad %%BoundingBox: comment.\n"
329 " REF: Page 39, %%BoundingBox:"));
330 }
331
332 if (saw_pages <= 0)
333 {
334 if (!status)
335 _cupsLangPuts(stdout, _("FAIL"));
336
337 status ++;
338 _cupsLangPuts(stdout, _(" Missing or bad %%Pages: comment.\n"
339 " REF: Page 43, %%Pages:"));
340 }
341
342 if (!saw_end_comments)
343 {
344 if (!status)
345 _cupsLangPuts(stdout, _("FAIL"));
346
347 status ++;
348 _cupsLangPuts(stdout, _(" Missing %%EndComments comment."
349 " REF: Page 41, %%EndComments"));
350 }
351
352 if (!saw_page)
353 {
354 if (!status)
355 _cupsLangPuts(stdout, _("FAIL"));
356
357 status ++;
358 _cupsLangPuts(stdout, _(" Missing or bad %%Page: comments.\n"
359 " REF: Page 53, %%Page:"));
360 }
361
362 if (level < 0)
363 {
364 if (!status)
365 _cupsLangPuts(stdout, _("FAIL"));
366
367 status ++;
368 _cupsLangPuts(stdout, _(" Too many %%EndDocument comments."));
369 }
370 else if (level > 0)
371 {
372 if (!status)
373 _cupsLangPuts(stdout, _("FAIL"));
374
375 status ++;
376 _cupsLangPuts(stdout, _(" Too many %%BeginDocument comments."));
377 }
378
379 if (saw_long_line > 1)
380 _cupsLangPrintf(stderr,
381 _(" Saw %d lines that exceeded 255 characters."),
382 saw_long_line);
383
384 if (!status)
385 _cupsLangPuts(stdout, _("PASS"));
386
387 if (binary)
388 _cupsLangPuts(stdout, _(" Warning: file contains binary data."));
389
390 if (version < 3.0f)
391 _cupsLangPrintf(stdout,
392 _(" Warning: obsolete DSC version %.1f in file."),
393 version);
394
395 if (saw_end_comments < 0)
396 _cupsLangPuts(stdout, _(" Warning: no %%EndComments comment in file."));
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 {
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
422 exit(1);
423 }