]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/cupstestppd.c
Load cups into easysw/current.
[thirdparty/cups.git] / systemv / cupstestppd.c
CommitLineData
ef416fc2 1/*
2 * "$Id: cupstestppd.c 4906 2006-01-10 20:53:28Z mike $"
3 *
4 * PPD test program for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * PostScript is a trademark of Adobe Systems, Inc.
25 *
26 * This file is subject to the Apple OS-Developed Software exception.
27 *
28 * Contents:
29 *
30 * main() - Main entry for test program.
31 * show_conflicts() - Show option conflicts in a PPD file.
32 * usage() - Show program usage...
33 */
34
35/*
36 * Include necessary headers...
37 */
38
39#include <cups/string.h>
40#include <cups/cups.h>
41#include <cups/i18n.h>
42#include <errno.h>
43#include <stdlib.h>
44
45
46/*
47 * Error codes...
48 */
49
50#define ERROR_NONE 0
51#define ERROR_USAGE 1
52#define ERROR_FILE_OPEN 2
53#define ERROR_PPD_FORMAT 3
54#define ERROR_CONFORMANCE 4
55
56
57/*
58 * Local functions...
59 */
60
61void show_conflicts(ppd_file_t *ppd);
62void usage(void);
63
64
65/*
66 * 'main()' - Main entry for test program.
67 */
68
69int /* O - Exit status */
70main(int argc, /* I - Number of command-line arguments */
71 char *argv[]) /* I - Command-line arguments */
72{
73 int i, j, k, m, n; /* Looping vars */
74 int len; /* Length of option name */
75 char *opt; /* Option character */
76 const char *ptr; /* Pointer into string */
77 int files; /* Number of files */
78 int verbose; /* Want verbose output? */
79 int status; /* Exit status */
80 int errors; /* Number of conformance errors */
81 int ppdversion; /* PPD spec version in PPD file */
82 ppd_status_t error; /* Status of ppdOpen*() */
83 int line; /* Line number for error */
84 int xdpi, /* X resolution */
85 ydpi; /* Y resolution */
86 ppd_file_t *ppd; /* PPD file record */
87 ppd_attr_t *attr; /* PPD attribute */
88 ppd_size_t *size; /* Size record */
89 ppd_group_t *group; /* UI group */
90 ppd_option_t *option; /* Standard UI option */
91 ppd_group_t *group2; /* UI group */
92 ppd_option_t *option2; /* Standard UI option */
93 ppd_choice_t *choice; /* Standard UI option choice */
94 static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
95 static char *sections[] = { "ANY", "DOCUMENT", "EXIT",
96 "JCL", "PAGE", "PROLOG" };
97
98
99 /*
100 * Display PPD files for each file listed on the command-line...
101 */
102
103 ppdSetConformance(PPD_CONFORM_STRICT);
104
105 verbose = 0;
106 ppd = NULL;
107 files = 0;
108 status = ERROR_NONE;
109
110 for (i = 1; i < argc; i ++)
111 if (argv[i][0] == '-' && argv[i][1])
112 {
113 for (opt = argv[i] + 1; *opt; opt ++)
114 switch (*opt)
115 {
116 case 'q' : /* Quiet mode */
117 if (verbose > 0)
118 {
119 _cupsLangPuts(stderr, NULL,
120 _("cupstestppd: The -q option is incompatible "
121 "with the -v option.\n"));
122 return (1);
123 }
124
125 verbose --;
126 break;
127
128 case 'r' : /* Relaxed mode */
129 ppdSetConformance(PPD_CONFORM_RELAXED);
130 break;
131
132 case 'v' : /* Verbose mode */
133 if (verbose < 0)
134 {
135 _cupsLangPuts(stderr, NULL,
136 _("cupstestppd: The -v option is incompatible "
137 "with the -q option.\n"));
138 return (1);
139 }
140
141 verbose ++;
142 break;
143
144 default :
145 usage();
146 break;
147 }
148 }
149 else
150 {
151 /*
152 * Open the PPD file...
153 */
154
155 if (files && verbose >= 0)
156 _cupsLangPuts(stdout, NULL, "\n");
157
158 files ++;
159
160 if (argv[i][0] == '-')
161 {
162 /*
163 * Read from stdin...
164 */
165
166 if (verbose >= 0)
167 printf("(stdin):");
168
169 ppd = ppdOpen(stdin);
170 }
171 else
172 {
173 /*
174 * Read from a file...
175 */
176
177 if (verbose >= 0)
178 printf("%s:", argv[i]);
179
180 ppd = ppdOpenFile(argv[i]);
181 }
182
183 if (ppd == NULL)
184 {
185 error = ppdLastError(&line);
186
187 if (error <= PPD_ALLOC_ERROR)
188 {
189 status = ERROR_FILE_OPEN;
190
191 if (verbose >= 0)
192 _cupsLangPrintf(stdout, NULL,
193 _(" FAIL\n"
194 " **FAIL** Unable to open PPD file - %s\n"),
195 strerror(errno));
196 }
197 else
198 {
199 status = ERROR_PPD_FORMAT;
200
201 if (verbose >= 0)
202 {
203 _cupsLangPrintf(stdout, NULL,
204 _(" FAIL\n"
205 " **FAIL** Unable to open PPD file - "
206 "%s on line %d.\n"),
207 ppdErrorString(error), line);
208
209 switch (error)
210 {
211 case PPD_MISSING_PPDADOBE4 :
212 _cupsLangPuts(stdout, NULL,
213 _(" REF: Page 42, section 5.2.\n"));
214 break;
215 case PPD_MISSING_VALUE :
216 _cupsLangPuts(stdout, NULL,
217 _(" REF: Page 20, section 3.4.\n"));
218 break;
219 case PPD_BAD_OPEN_GROUP :
220 case PPD_NESTED_OPEN_GROUP :
221 _cupsLangPuts(stdout, NULL,
222 _(" REF: Pages 45-46, section 5.2.\n"));
223 break;
224 case PPD_BAD_OPEN_UI :
225 case PPD_NESTED_OPEN_UI :
226 _cupsLangPuts(stdout, NULL,
227 _(" REF: Pages 42-45, section 5.2.\n"));
228 break;
229 case PPD_BAD_ORDER_DEPENDENCY :
230 _cupsLangPuts(stdout, NULL,
231 _(" REF: Pages 48-49, section 5.2.\n"));
232 break;
233 case PPD_BAD_UI_CONSTRAINTS :
234 _cupsLangPuts(stdout, NULL,
235 _(" REF: Pages 52-54, section 5.2.\n"));
236 break;
237 case PPD_MISSING_ASTERISK :
238 _cupsLangPuts(stdout, NULL,
239 _(" REF: Page 15, section 3.2.\n"));
240 break;
241 case PPD_LINE_TOO_LONG :
242 _cupsLangPuts(stdout, NULL,
243 _(" REF: Page 15, section 3.1.\n"));
244 break;
245 case PPD_ILLEGAL_CHARACTER :
246 _cupsLangPuts(stdout, NULL,
247 _(" REF: Page 15, section 3.1.\n"));
248 break;
249 case PPD_ILLEGAL_MAIN_KEYWORD :
250 _cupsLangPuts(stdout, NULL,
251 _(" REF: Pages 16-17, section 3.2.\n"));
252 break;
253 case PPD_ILLEGAL_OPTION_KEYWORD :
254 _cupsLangPuts(stdout, NULL,
255 _(" REF: Page 19, section 3.3.\n"));
256 break;
257 case PPD_ILLEGAL_TRANSLATION :
258 _cupsLangPuts(stdout, NULL,
259 _(" REF: Page 27, section 3.5.\n"));
260 break;
261 default :
262 break;
263 }
264 }
265 }
266
267 continue;
268 }
269
270 /*
271 * Show the header and then perform basic conformance tests (limited
272 * only by what the CUPS PPD functions actually load...)
273 */
274
275 errors = 0;
276 ppdversion = 43;
277
278 if (verbose > 0)
279 _cupsLangPuts(stdout, NULL,
280 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
281
282 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
283 attr->value)
284 ppdversion = (int)(10 * atof(attr->value) + 0.5);
285
286 if (verbose > 0)
287 {
288 /*
289 * Look for default keywords with no matching option...
290 */
291
292 for (i = 0; i < ppd->num_attrs; i ++)
293 {
294 attr = ppd->attrs[i];
295
296 if (!strcmp(attr->name, "DefaultColorSpace") ||
297 !strcmp(attr->name, "DefaultFont") ||
298 !strcmp(attr->name, "DefaultImageableArea") ||
299 !strcmp(attr->name, "DefaultOutputOrder") ||
300 !strcmp(attr->name, "DefaultPaperDimension") ||
301 !strcmp(attr->name, "DefaultTransfer"))
302 continue;
303
304 if (!strncmp(attr->name, "Default", 7) &&
305 !ppdFindOption(ppd, attr->name + 7))
306 _cupsLangPrintf(stdout, NULL,
307 _(" WARN %s has no corresponding "
308 "options!\n"),
309 attr->name);
310 }
311 }
312
313 if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
314 {
315 if (verbose >= 0)
316 {
317 if (!errors && !verbose)
318 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
319
320 _cupsLangPuts(stdout, NULL,
321 _(" **FAIL** REQUIRED DefaultImageableArea\n"
322 " REF: Page 102, section 5.15.\n"));
323 }
324
325 errors ++;
326 }
327 else if (ppdPageSize(ppd, attr->value) == NULL &&
328 strcmp(attr->value, "Unknown"))
329 {
330 if (verbose >= 0)
331 {
332 if (!errors && !verbose)
333 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
334
335 _cupsLangPrintf(stdout, NULL,
336 _(" **FAIL** BAD DefaultImageableArea %s!\n"
337 " REF: Page 102, section 5.15.\n"),
338 attr->value);
339 }
340
341 errors ++;
342 }
343 else
344 {
345 if (verbose > 0)
346 _cupsLangPuts(stdout, NULL, _(" PASS DefaultImageableArea\n"));
347 }
348
349 if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL)
350 {
351 if (verbose >= 0)
352 {
353 if (!errors && !verbose)
354 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
355
356 _cupsLangPuts(stdout, NULL,
357 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
358 " REF: Page 103, section 5.15.\n"));
359 }
360
361 errors ++;
362 }
363 else if (ppdPageSize(ppd, attr->value) == NULL &&
364 strcmp(attr->value, "Unknown"))
365 {
366 if (verbose >= 0)
367 {
368 if (!errors && !verbose)
369 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
370
371 _cupsLangPrintf(stdout, NULL,
372 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
373 " REF: Page 103, section 5.15.\n"),
374 attr->value);
375 }
376
377 errors ++;
378 }
379 else if (verbose > 0)
380 _cupsLangPuts(stdout, NULL, _(" PASS DefaultPaperDimension\n"));
381
382 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
383 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
384 {
385 /*
386 * Verify that we have a default choice...
387 */
388
389 if (option->defchoice[0])
390 {
391 if (ppdFindChoice(option, option->defchoice) == NULL &&
392 strcmp(option->defchoice, "Unknown"))
393 {
394 if (verbose >= 0)
395 {
396 if (!errors && !verbose)
397 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
398
399 _cupsLangPrintf(stdout, NULL,
400 _(" **FAIL** BAD Default%s %s\n"
401 " REF: Page 40, section 4.5.\n"),
402 option->keyword, option->defchoice);
403 }
404
405 errors ++;
406 }
407 else if (verbose > 0)
408 _cupsLangPrintf(stdout, NULL,
409 _(" PASS Default%s\n"),
410 option->keyword);
411 }
412 else
413 {
414 if (verbose >= 0)
415 {
416 if (!errors && !verbose)
417 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
418
419 _cupsLangPrintf(stdout, NULL,
420 _(" **FAIL** REQUIRED Default%s\n"
421 " REF: Page 40, section 4.5.\n"),
422 option->keyword);
423 }
424
425 errors ++;
426 }
427 }
428
429 if (ppdFindAttr(ppd, "FileVersion", NULL) != NULL)
430 {
431 if (verbose > 0)
432 _cupsLangPuts(stdout, NULL, _(" PASS FileVersion\n"));
433 }
434 else
435 {
436 if (verbose >= 0)
437 {
438 if (!errors && !verbose)
439 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
440
441 _cupsLangPuts(stdout, NULL,
442 _(" **FAIL** REQUIRED FileVersion\n"
443 " REF: Page 56, section 5.3.\n"));
444 }
445
446 errors ++;
447 }
448
449 if (ppdFindAttr(ppd, "FormatVersion", NULL) != NULL)
450 {
451 if (verbose > 0)
452 _cupsLangPuts(stdout, NULL, _(" PASS FormatVersion\n"));
453 }
454 else
455 {
456 if (verbose >= 0)
457 {
458 if (!errors && !verbose)
459 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
460
461 _cupsLangPuts(stdout, NULL,
462 _(" **FAIL** REQUIRED FormatVersion\n"
463 " REF: Page 56, section 5.3.\n"));
464 }
465
466 errors ++;
467 }
468
469 if (ppd->lang_encoding != NULL)
470 {
471 if (verbose > 0)
472 _cupsLangPuts(stdout, NULL, _(" PASS LanguageEncoding\n"));
473 }
474 else if (ppdversion > 40)
475 {
476 if (verbose >= 0)
477 {
478 if (!errors && !verbose)
479 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
480
481 _cupsLangPuts(stdout, NULL,
482 _(" **FAIL** REQUIRED LanguageEncoding\n"
483 " REF: Pages 56-57, section 5.3.\n"));
484 }
485
486 errors ++;
487 }
488
489 if (ppd->lang_version != NULL)
490 {
491 if (verbose > 0)
492 _cupsLangPuts(stdout, NULL, _(" PASS LanguageVersion\n"));
493 }
494 else
495 {
496 if (verbose >= 0)
497 {
498 if (!errors && !verbose)
499 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
500
501 _cupsLangPuts(stdout, NULL,
502 _(" **FAIL** REQUIRED LanguageVersion\n"
503 " REF: Pages 57-58, section 5.3.\n"));
504 }
505
506 errors ++;
507 }
508
509 if (ppd->manufacturer != NULL)
510 {
511 if (!strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) ||
512 !strncasecmp(ppd->manufacturer, "Hewlett Packard", 15))
513 {
514 if (verbose >= 0)
515 {
516 if (!errors && !verbose)
517 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
518
519 _cupsLangPuts(stdout, NULL,
520 _(" **FAIL** BAD Manufacturer (should be "
521 "\"HP\")\n"
522 " REF: Page 211, table D.1.\n"));
523 }
524
525 errors ++;
526 }
527 else if (verbose > 0)
528 _cupsLangPuts(stdout, NULL, _(" PASS Manufacturer\n"));
529 }
530 else if (ppdversion >= 43)
531 {
532 if (verbose >= 0)
533 {
534 if (!errors && !verbose)
535 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
536
537 _cupsLangPuts(stdout, NULL,
538 _(" **FAIL** REQUIRED Manufacturer\n"
539 " REF: Pages 58-59, section 5.3.\n"));
540 }
541
542 errors ++;
543 }
544
545 if (ppd->modelname != NULL)
546 {
547 for (ptr = ppd->modelname; *ptr; ptr ++)
548 if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr))
549 break;
550
551 if (*ptr)
552 {
553 if (verbose >= 0)
554 {
555 if (!errors && !verbose)
556 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
557
558 _cupsLangPrintf(stdout, NULL,
559 _(" **FAIL** BAD ModelName - \"%c\" not "
560 "allowed in string.\n"
561 " REF: Pages 59-60, section 5.3.\n"),
562 *ptr);
563 }
564
565 errors ++;
566 }
567 else if (verbose > 0)
568 _cupsLangPuts(stdout, NULL, _(" PASS ModelName\n"));
569 }
570 else
571 {
572 if (verbose >= 0)
573 {
574 if (!errors && !verbose)
575 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
576
577 _cupsLangPuts(stdout, NULL,
578 _(" **FAIL** REQUIRED ModelName\n"
579 " REF: Pages 59-60, section 5.3.\n"));
580 }
581
582 errors ++;
583 }
584
585 if (ppd->nickname != NULL)
586 {
587 if (verbose > 0)
588 _cupsLangPuts(stdout, NULL, _(" PASS NickName\n"));
589 }
590 else
591 {
592 if (verbose >= 0)
593 {
594 if (!errors && !verbose)
595 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
596
597 _cupsLangPuts(stdout, NULL,
598 _(" **FAIL** REQUIRED NickName\n"
599 " REF: Page 60, section 5.3.\n"));
600 }
601
602 errors ++;
603 }
604
605 if (ppdFindOption(ppd, "PageSize") != NULL)
606 {
607 if (verbose > 0)
608 _cupsLangPuts(stdout, NULL, _(" PASS PageSize\n"));
609 }
610 else
611 {
612 if (verbose >= 0)
613 {
614 if (!errors && !verbose)
615 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
616
617 _cupsLangPuts(stdout, NULL,
618 _(" **FAIL** REQUIRED PageSize\n"
619 " REF: Pages 99-100, section 5.14.\n"));
620 }
621
622 errors ++;
623 }
624
625 if (ppdFindOption(ppd, "PageRegion") != NULL)
626 {
627 if (verbose > 0)
628 _cupsLangPuts(stdout, NULL, _(" PASS PageRegion\n"));
629 }
630 else
631 {
632 if (verbose >= 0)
633 {
634 if (!errors && !verbose)
635 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
636
637 _cupsLangPuts(stdout, NULL,
638 _(" **FAIL** REQUIRED PageRegion\n"
639 " REF: Page 100, section 5.14.\n"));
640 }
641
642 errors ++;
643 }
644
645 if (ppd->pcfilename != NULL)
646 {
647 if (verbose > 0)
648 _cupsLangPuts(stdout, NULL, _(" PASS PCFileName\n"));
649 }
650 else
651 {
652 if (verbose >= 0)
653 {
654 if (!errors && !verbose)
655 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
656
657 _cupsLangPuts(stdout, NULL,
658 _(" **FAIL** REQUIRED PCFileName\n"
659 " REF: Pages 61-62, section 5.3.\n"));
660 }
661
662 errors ++;
663 }
664
665 if (ppd->product != NULL)
666 {
667 if (ppd->product[0] != '(' ||
668 ppd->product[strlen(ppd->product) - 1] != ')')
669 {
670 if (verbose >= 0)
671 {
672 if (!errors && !verbose)
673 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
674
675 _cupsLangPuts(stdout, NULL,
676 _(" **FAIL** BAD Product - not \"(string)\".\n"
677 " REF: Page 62, section 5.3.\n"));
678 }
679
680 errors ++;
681 }
682 else if (verbose > 0)
683 _cupsLangPuts(stdout, NULL, _(" PASS Product\n"));
684 }
685 else
686 {
687 if (verbose >= 0)
688 {
689 if (!errors && !verbose)
690 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
691
692 _cupsLangPuts(stdout, NULL,
693 _(" **FAIL** REQUIRED Product\n"
694 " REF: Page 62, section 5.3.\n"));
695 }
696
697 errors ++;
698 }
699
700 if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL &&
701 attr->value != NULL)
702 {
703 char junkstr[255]; /* Temp string */
704 int junkint; /* Temp integer */
705
706
707 if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2)
708 {
709 if (verbose >= 0)
710 {
711 if (!errors && !verbose)
712 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
713
714 _cupsLangPuts(stdout, NULL,
715 _(" **FAIL** BAD PSVersion - not \"(string) "
716 "int\".\n"
717 " REF: Pages 62-64, section 5.3.\n"));
718 }
719
720 errors ++;
721 }
722 else if (verbose > 0)
723 _cupsLangPuts(stdout, NULL, _(" PASS PSVersion\n"));
724 }
725 else
726 {
727 if (verbose >= 0)
728 {
729 if (!errors && !verbose)
730 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
731
732 _cupsLangPuts(stdout, NULL,
733 _(" **FAIL** REQUIRED PSVersion\n"
734 " REF: Pages 62-64, section 5.3.\n"));
735 }
736
737 errors ++;
738 }
739
740 if (ppd->shortnickname != NULL)
741 {
742 if (strlen(ppd->shortnickname) > 31)
743 {
744 if (verbose >= 0)
745 {
746 if (!errors && !verbose)
747 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
748
749 _cupsLangPuts(stdout, NULL,
750 _(" **FAIL** BAD ShortNickName - longer "
751 "than 31 chars.\n"
752 " REF: Pages 64-65, section 5.3.\n"));
753 }
754
755 errors ++;
756 }
757 else if (verbose > 0)
758 _cupsLangPuts(stdout, NULL, _(" PASS ShortNickName\n"));
759 }
760 else if (ppdversion >= 43)
761 {
762 if (verbose >= 0)
763 {
764 if (!errors && !verbose)
765 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
766
767 _cupsLangPuts(stdout, NULL,
768 _(" **FAIL** REQUIRED ShortNickName\n"
769 " REF: Page 64-65, section 5.3.\n"));
770 }
771
772 errors ++;
773 }
774
775 if (ppd->patches != NULL && strchr(ppd->patches, '\"') &&
776 strstr(ppd->patches, "*End"))
777 {
778 if (verbose >= 0)
779 {
780 if (!errors && !verbose)
781 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
782
783 _cupsLangPuts(stdout, NULL,
784 _(" **FAIL** BAD JobPatchFile attribute in file\n"
785 " REF: Page 24, section 3.4.\n"));
786 }
787
788 errors ++;
789 }
790
791 /*
792 * Check for page sizes without the corresponding ImageableArea or
793 * PaperDimension values...
794 */
795
796 if (ppd->num_sizes == 0)
797 {
798 if (verbose >= 0)
799 {
800 if (!errors && !verbose)
801 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
802
803 _cupsLangPuts(stdout, NULL,
804 _(" **FAIL** REQUIRED PageSize\n"
805 " REF: Page 41, section 5.\n"
806 " REF: Page 99, section 5.14.\n"));
807 }
808
809 errors ++;
810 }
811 else
812 {
813 for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++)
814 {
815 /*
816 * Don't check custom size...
817 */
818
819 if (!strcmp(size->name, "Custom"))
820 continue;
821
822 /*
823 * Check for ImageableArea...
824 */
825
826 if (size->left == 0.0 && size->bottom == 0.0 &&
827 size->right == 0.0 && size->top == 0.0)
828 {
829 if (verbose >= 0)
830 {
831 if (!errors && !verbose)
832 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
833
834 _cupsLangPrintf(stdout, NULL,
835 _(" **FAIL** REQUIRED ImageableArea for "
836 "PageSize %s\n"
837 " REF: Page 41, section 5.\n"
838 " REF: Page 102, section 5.15.\n"),
839 size->name);
840 }
841
842 errors ++;
843 }
844
845 /*
846 * Check for PaperDimension...
847 */
848
849 if (size->width == 0.0 && size->length == 0.0)
850 {
851 if (verbose >= 0)
852 {
853 if (!errors && !verbose)
854 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
855
856 _cupsLangPrintf(stdout, NULL,
857 _(" **FAIL** REQUIRED PaperDimension "
858 "for PageSize %s\n"
859 " REF: Page 41, section 5.\n"
860 " REF: Page 103, section 5.15.\n"),
861 size->name);
862 }
863
864 errors ++;
865 }
866 }
867 }
868
869 /*
870 * Check for valid Resolution, JCLResolution, or SetResolution values...
871 */
872
873 if ((option = ppdFindOption(ppd, "Resolution")) == NULL)
874 if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL)
875 option = ppdFindOption(ppd, "SetResolution");
876
877 if (option != NULL)
878 {
879 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
880 {
881 /*
882 * Verify that all resolution options are of the form NNNdpi
883 * or NNNxNNNdpi...
884 */
885
886 xdpi = strtol(choice->choice, (char **)&ptr, 10);
887 if (ptr > choice->choice && xdpi > 0)
888 {
889 if (*ptr == 'x')
890 ydpi = strtol(ptr + 1, (char **)&ptr, 10);
891 else
892 ydpi = xdpi;
893 }
894 else
895 ydpi = xdpi;
896
897 if (xdpi <= 0 || ydpi <= 0 || strcmp(ptr, "dpi"))
898 {
899 if (verbose >= 0)
900 {
901 if (!errors && !verbose)
902 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
903
904 _cupsLangPrintf(stdout, NULL,
905 _(" **FAIL** Bad %s choice %s!\n"
906 " REF: Page 84, section 5.9\n"),
907 option->keyword, choice->choice);
908 }
909
910 errors ++;
911 }
912 }
913 }
914
915 /*
916 * Check for a duplex option, and for standard values...
917 */
918
919 if ((option = ppdFindOption(ppd, "Duplex")) == NULL)
920 if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
921 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
922 option = ppdFindOption(ppd, "KD03Duplex");
923
924 if (option != NULL)
925 {
926 if (ppdFindChoice(option, "None") == NULL)
927 {
928 if (verbose >= 0)
929 {
930 if (!errors && !verbose)
931 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
932
933 _cupsLangPrintf(stdout, NULL,
934 _(" **FAIL** REQUIRED %s does not define "
935 "choice None!\n"
936 " REF: Page 122, section 5.17\n"),
937 option->keyword);
938 }
939
940 errors ++;
941 }
942
943 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
944 if (strcmp(choice->choice, "None") &&
945 strcmp(choice->choice, "DuplexNoTumble") &&
946 strcmp(choice->choice, "DuplexTumble") &&
947 strcmp(choice->choice, "SimplexTumble"))
948 {
949 if (verbose >= 0)
950 {
951 if (!errors && !verbose)
952 _cupsLangPuts(stdout, NULL, _(" FAIL\n"));
953
954 _cupsLangPrintf(stdout, NULL,
955 _(" **FAIL** Bad %s choice %s!\n"
956 " REF: Page 122, section 5.17\n"),
957 option->keyword, choice->choice);
958 }
959
960 errors ++;
961 }
962 }
963
964 if (errors)
965 status = ERROR_CONFORMANCE;
966 else if (!verbose)
967 _cupsLangPuts(stdout, NULL, _(" PASS\n"));
968
969 if (verbose >= 0)
970 {
971 if (option &&
972 strcmp(option->keyword, "Duplex") &&
973 strcmp(option->keyword, "JCLDuplex"))
974 {
975 _cupsLangPrintf(stdout, NULL,
976 _(" WARN Duplex option keyword %s "
977 "should be named Duplex or JCLDuplex!\n"
978 " REF: Page 122, section 5.17\n"),
979 option->keyword);
980 }
981
982 ppdMarkDefaults(ppd);
983 if (ppdConflicts(ppd))
984 {
985 _cupsLangPuts(stdout, NULL,
986 _(" WARN Default choices conflicting!\n"));
987
988 show_conflicts(ppd);
989 }
990
991 if (ppdversion < 43)
992 {
993 _cupsLangPrintf(stdout, NULL,
994 _(" WARN Obsolete PPD version %.1f!\n"
995 " REF: Page 42, section 5.2.\n"),
996 0.1f * ppdversion);
997 }
998
999 if (!ppd->lang_encoding && ppdversion < 41)
1000 {
1001 _cupsLangPuts(stdout, NULL,
1002 _(" WARN LanguageEncoding required by PPD "
1003 "4.3 spec.\n"
1004 " REF: Pages 56-57, section 5.3.\n"));
1005 }
1006
1007 if (!ppd->manufacturer && ppdversion < 43)
1008 {
1009 _cupsLangPuts(stdout, NULL,
1010 _(" WARN Manufacturer required by PPD "
1011 "4.3 spec.\n"
1012 " REF: Pages 58-59, section 5.3.\n"));
1013 }
1014
1015 /*
1016 * Treat a PCFileName attribute longer than 12 characters as
1017 * a warning and not a hard error...
1018 */
1019
1020 if (ppd->pcfilename && strlen(ppd->pcfilename) > 12)
1021 {
1022 _cupsLangPuts(stdout, NULL,
1023 _(" WARN PCFileName longer than 8.3 in "
1024 "violation of PPD spec.\n"
1025 " REF: Pages 61-62, section 5.3.\n"));
1026 }
1027
1028 if (!ppd->shortnickname && ppdversion < 43)
1029 {
1030 _cupsLangPuts(stdout, NULL,
1031 _(" WARN ShortNickName required by PPD "
1032 "4.3 spec.\n"
1033 " REF: Pages 64-65, section 5.3.\n"));
1034 }
1035
1036 /*
1037 * Check the Protocols line and flag PJL + BCP since TBCP is
1038 * usually used with PJL...
1039 */
1040
1041 if (ppd->protocols)
1042 {
1043 if (strstr(ppd->protocols, "PJL") &&
1044 strstr(ppd->protocols, "BCP") &&
1045 !strstr(ppd->protocols, "TBCP"))
1046 {
1047 _cupsLangPuts(stdout, NULL,
1048 _(" WARN Protocols contains both PJL "
1049 "and BCP; expected TBCP.\n"
1050 " REF: Pages 78-79, section 5.7.\n"));
1051 }
1052
1053 if (strstr(ppd->protocols, "PJL") &&
1054 (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps))
1055 {
1056 _cupsLangPuts(stdout, NULL,
1057 _(" WARN Protocols contains PJL but JCL "
1058 "attributes are not set.\n"
1059 " REF: Pages 78-79, section 5.7.\n"));
1060 }
1061 }
1062
1063 /*
1064 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1065 * which are errors according to the spec but won't cause problems
1066 * with CUPS specifically...
1067 */
1068
1069 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1070 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1071 {
1072 len = strlen(option->keyword);
1073
1074 for (m = 0, group2 = ppd->groups;
1075 m < ppd->num_groups;
1076 m ++, group2 ++)
1077 for (n = 0, option2 = group2->options;
1078 n < group2->num_options;
1079 n ++, option2 ++)
1080 if (option != option2 &&
1081 len < strlen(option2->keyword) &&
1082 !strncmp(option->keyword, option2->keyword, len))
1083 {
1084 _cupsLangPrintf(stdout, NULL,
1085 _(" WARN %s shares a common "
1086 "prefix with %s\n"
1087 " REF: Page 15, section "
1088 "3.2.\n"),
1089 option->keyword, option2->keyword);
1090 }
1091 }
1092 }
1093
1094 if (verbose > 0)
1095 {
1096 if (errors)
1097 _cupsLangPrintf(stdout, NULL, _(" %d ERROR%s FOUND\n"),
1098 errors, errors == 1 ? "" : "S");
1099 else
1100 _cupsLangPuts(stdout, NULL, _(" NO ERRORS FOUND\n"));
1101 }
1102
1103
1104 /*
1105 * Then list the options, if "-v" was provided...
1106 */
1107
1108 if (verbose > 1)
1109 {
1110 _cupsLangPrintf(stdout, NULL,
1111 "\n"
1112 " language_level = %d\n"
1113 " color_device = %s\n"
1114 " variable_sizes = %s\n"
1115 " landscape = %d\n",
1116 ppd->language_level,
1117 ppd->color_device ? "TRUE" : "FALSE",
1118 ppd->variable_sizes ? "TRUE" : "FALSE",
1119 ppd->landscape);
1120
1121 switch (ppd->colorspace)
1122 {
1123 case PPD_CS_CMYK :
1124 _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_CMYK\n");
1125 break;
1126 case PPD_CS_CMY :
1127 _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_CMY\n");
1128 break;
1129 case PPD_CS_GRAY :
1130 _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_GRAY\n");
1131 break;
1132 case PPD_CS_RGB :
1133 _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_RGB\n");
1134 break;
1135 default :
1136 _cupsLangPuts(stdout, NULL, " colorspace = <unknown>\n");
1137 break;
1138 }
1139
1140 _cupsLangPrintf(stdout, NULL, " num_emulations = %d\n",
1141 ppd->num_emulations);
1142 for (j = 0; j < ppd->num_emulations; j ++)
1143 _cupsLangPrintf(stdout, NULL, " emulations[%d] = %s\n",
1144 j, ppd->emulations[j].name);
1145
1146 _cupsLangPrintf(stdout, NULL, " lang_encoding = %s\n",
1147 ppd->lang_encoding);
1148 _cupsLangPrintf(stdout, NULL, " lang_version = %s\n",
1149 ppd->lang_version);
1150 _cupsLangPrintf(stdout, NULL, " modelname = %s\n", ppd->modelname);
1151 _cupsLangPrintf(stdout, NULL, " ttrasterizer = %s\n",
1152 ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer);
1153 _cupsLangPrintf(stdout, NULL, " manufacturer = %s\n",
1154 ppd->manufacturer);
1155 _cupsLangPrintf(stdout, NULL, " product = %s\n", ppd->product);
1156 _cupsLangPrintf(stdout, NULL, " nickname = %s\n", ppd->nickname);
1157 _cupsLangPrintf(stdout, NULL, " shortnickname = %s\n",
1158 ppd->shortnickname);
1159 _cupsLangPrintf(stdout, NULL, " patches = %d bytes\n",
1160 ppd->patches == NULL ? 0 : (int)strlen(ppd->patches));
1161
1162 _cupsLangPrintf(stdout, NULL, " num_groups = %d\n", ppd->num_groups);
1163 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1164 {
1165 _cupsLangPrintf(stdout, NULL, " group[%d] = %s\n",
1166 j, group->text);
1167
1168 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1169 {
1170 _cupsLangPrintf(stdout, NULL,
1171 " options[%d] = %s (%s) %s %s %.0f "
1172 "(%d choices)\n",
1173 k, option->keyword, option->text, uis[option->ui],
1174 sections[option->section], option->order,
1175 option->num_choices);
1176
1177 if (!strcmp(option->keyword, "PageSize") ||
1178 !strcmp(option->keyword, "PageRegion"))
1179 {
1180 for (m = option->num_choices, choice = option->choices;
1181 m > 0;
1182 m --, choice ++)
1183 {
1184 size = ppdPageSize(ppd, choice->choice);
1185
1186 if (size == NULL)
1187 _cupsLangPrintf(stdout, NULL,
1188 " %s (%s) = ERROR",
1189 choice->choice, choice->text);
1190 else
1191 _cupsLangPrintf(stdout, NULL,
1192 " %s (%s) = %.2fx%.2fin "
1193 "(%.1f,%.1f,%.1f,%.1f)",
1194 choice->choice, choice->text,
1195 size->width / 72.0, size->length / 72.0,
1196 size->left / 72.0, size->bottom / 72.0,
1197 size->right / 72.0, size->top / 72.0);
1198
1199 if (!strcmp(option->defchoice, choice->choice))
1200 _cupsLangPuts(stdout, NULL, " *\n");
1201 else
1202 _cupsLangPuts(stdout, NULL, "\n");
1203 }
1204 }
1205 else
1206 {
1207 for (m = option->num_choices, choice = option->choices;
1208 m > 0;
1209 m --, choice ++)
1210 {
1211 _cupsLangPrintf(stdout, NULL, " %s (%s)",
1212 choice->choice, choice->text);
1213
1214 if (!strcmp(option->defchoice, choice->choice))
1215 _cupsLangPuts(stdout, NULL, " *\n");
1216 else
1217 _cupsLangPuts(stdout, NULL, "\n");
1218 }
1219 }
1220 }
1221 }
1222
1223 _cupsLangPrintf(stdout, NULL, " num_profiles = %d\n",
1224 ppd->num_profiles);
1225 for (j = 0; j < ppd->num_profiles; j ++)
1226 _cupsLangPrintf(stdout, NULL,
1227 " profiles[%d] = %s/%s %.3f %.3f "
1228 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1229 j, ppd->profiles[j].resolution,
1230 ppd->profiles[j].media_type,
1231 ppd->profiles[j].gamma, ppd->profiles[j].density,
1232 ppd->profiles[j].matrix[0][0],
1233 ppd->profiles[j].matrix[0][1],
1234 ppd->profiles[j].matrix[0][2],
1235 ppd->profiles[j].matrix[1][0],
1236 ppd->profiles[j].matrix[1][1],
1237 ppd->profiles[j].matrix[1][2],
1238 ppd->profiles[j].matrix[2][0],
1239 ppd->profiles[j].matrix[2][1],
1240 ppd->profiles[j].matrix[2][2]);
1241
1242 _cupsLangPrintf(stdout, NULL, " num_fonts = %d\n", ppd->num_fonts);
1243 for (j = 0; j < ppd->num_fonts; j ++)
1244 _cupsLangPrintf(stdout, NULL, " fonts[%d] = %s\n",
1245 j, ppd->fonts[j]);
1246
1247 _cupsLangPrintf(stdout, NULL, " num_attrs = %d\n", ppd->num_attrs);
1248 for (j = 0; j < ppd->num_attrs; j ++)
1249 _cupsLangPrintf(stdout, NULL,
1250 " attrs[%d] = %s %s%s%s: \"%s\"\n", j,
1251 ppd->attrs[j]->name, ppd->attrs[j]->spec,
1252 ppd->attrs[j]->text[0] ? "/" : "",
1253 ppd->attrs[j]->text,
1254 ppd->attrs[j]->value ?
1255 ppd->attrs[j]->value : "(null)");
1256 }
1257
1258 ppdClose(ppd);
1259 }
1260
1261 if (!files)
1262 usage();
1263
1264 return (status);
1265}
1266
1267
1268/*
1269 * 'show_conflicts()' - Show option conflicts in a PPD file.
1270 */
1271
1272void
1273show_conflicts(ppd_file_t *ppd) /* I - PPD to check */
1274{
1275 int i, j; /* Looping variables */
1276 ppd_const_t *c; /* Current constraint */
1277 ppd_option_t *o1, *o2; /* Options */
1278 ppd_choice_t *c1, *c2; /* Choices */
1279
1280
1281 /*
1282 * Loop through all of the UI constraints and report any options
1283 * that conflict...
1284 */
1285
1286 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
1287 {
1288 /*
1289 * Grab pointers to the first option...
1290 */
1291
1292 o1 = ppdFindOption(ppd, c->option1);
1293
1294 if (o1 == NULL)
1295 continue;
1296 else if (c->choice1[0] != '\0')
1297 {
1298 /*
1299 * This constraint maps to a specific choice.
1300 */
1301
1302 c1 = ppdFindChoice(o1, c->choice1);
1303 }
1304 else
1305 {
1306 /*
1307 * This constraint applies to any choice for this option.
1308 */
1309
1310 for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
1311 if (c1->marked)
1312 break;
1313
1314 if (j == 0 ||
1315 !strcasecmp(c1->choice, "None") ||
1316 !strcasecmp(c1->choice, "Off") ||
1317 !strcasecmp(c1->choice, "False"))
1318 c1 = NULL;
1319 }
1320
1321 /*
1322 * Grab pointers to the second option...
1323 */
1324
1325 o2 = ppdFindOption(ppd, c->option2);
1326
1327 if (o2 == NULL)
1328 continue;
1329 else if (c->choice2[0] != '\0')
1330 {
1331 /*
1332 * This constraint maps to a specific choice.
1333 */
1334
1335 c2 = ppdFindChoice(o2, c->choice2);
1336 }
1337 else
1338 {
1339 /*
1340 * This constraint applies to any choice for this option.
1341 */
1342
1343 for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
1344 if (c2->marked)
1345 break;
1346
1347 if (j == 0 ||
1348 !strcasecmp(c2->choice, "None") ||
1349 !strcasecmp(c2->choice, "Off") ||
1350 !strcasecmp(c2->choice, "False"))
1351 c2 = NULL;
1352 }
1353
1354 /*
1355 * If both options are marked then there is a conflict...
1356 */
1357
1358 if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
1359 _cupsLangPrintf(stdout, NULL,
1360 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
1361 " (constraint=\"%s %s %s %s\")\n"),
1362 o1->keyword, c1->choice, o2->keyword, c2->choice,
1363 c->option1, c->choice1, c->option2, c->choice2);
1364 }
1365}
1366
1367
1368/*
1369 * 'usage()' - Show program usage...
1370 */
1371
1372void
1373usage(void)
1374{
1375 _cupsLangPuts(stdout, NULL,
1376 _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] "
1377 "[... filenameN.ppd[.gz]]\n"
1378 " program | cupstestppd [-q] [-r] [-v[v]] -\n"));
1379
1380 exit(ERROR_USAGE);
1381}
1382
1383
1384/*
1385 * End of "$Id: cupstestppd.c 4906 2006-01-10 20:53:28Z mike $".
1386 */