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