2 * "$Id: cupstestppd.c 5189 2006-02-27 01:45:57Z mike $"
4 * PPD test program for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * PostScript is a trademark of Adobe Systems, Inc.
26 * This file is subject to the Apple OS-Developed Software exception.
30 * main() - Main entry for test program.
31 * show_conflicts() - Show option conflicts in a PPD file.
32 * usage() - Show program usage...
36 * Include necessary headers...
39 #include <cups/string.h>
40 #include <cups/cups.h>
41 #include <cups/i18n.h>
77 void check_basics(const char *filename
);
78 void show_conflicts(ppd_file_t
*ppd
);
83 * 'main()' - Main entry for test program.
86 int /* O - Exit status */
87 main(int argc
, /* I - Number of command-line arguments */
88 char *argv
[]) /* I - Command-line arguments */
90 int i
, j
, k
, m
, n
; /* Looping vars */
91 int len
; /* Length of option name */
92 char *opt
; /* Option character */
93 const char *ptr
; /* Pointer into string */
94 int files
; /* Number of files */
95 int verbose
; /* Want verbose output? */
96 int status
; /* Exit status */
97 int errors
; /* Number of conformance errors */
98 int ppdversion
; /* PPD spec version in PPD file */
99 ppd_status_t error
; /* Status of ppdOpen*() */
100 int line
; /* Line number for error */
101 int xdpi
, /* X resolution */
102 ydpi
; /* Y resolution */
103 ppd_file_t
*ppd
; /* PPD file record */
104 ppd_attr_t
*attr
; /* PPD attribute */
105 ppd_size_t
*size
; /* Size record */
106 ppd_group_t
*group
; /* UI group */
107 ppd_option_t
*option
; /* Standard UI option */
108 ppd_group_t
*group2
; /* UI group */
109 ppd_option_t
*option2
; /* Standard UI option */
110 ppd_choice_t
*choice
; /* Standard UI option choice */
111 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
112 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
113 "JCL", "PAGE", "PROLOG" };
117 * Display PPD files for each file listed on the command-line...
120 ppdSetConformance(PPD_CONFORM_STRICT
);
127 for (i
= 1; i
< argc
; i
++)
128 if (argv
[i
][0] == '-' && argv
[i
][1])
130 for (opt
= argv
[i
] + 1; *opt
; opt
++)
133 case 'q' : /* Quiet mode */
136 _cupsLangPuts(stderr
,
137 _("cupstestppd: The -q option is incompatible "
138 "with the -v option.\n"));
145 case 'r' : /* Relaxed mode */
146 ppdSetConformance(PPD_CONFORM_RELAXED
);
149 case 'v' : /* Verbose mode */
152 _cupsLangPuts(stderr
,
153 _("cupstestppd: The -v option is incompatible "
154 "with the -q option.\n"));
169 * Open the PPD file...
172 if (files
&& verbose
>= 0)
173 _cupsLangPuts(stdout
, "\n");
177 if (argv
[i
][0] == '-')
186 ppd
= ppdOpen(stdin
);
191 * Read from a file...
195 printf("%s:", argv
[i
]);
197 ppd
= ppdOpenFile(argv
[i
]);
202 error
= ppdLastError(&line
);
204 if (error
<= PPD_ALLOC_ERROR
)
206 status
= ERROR_FILE_OPEN
;
209 _cupsLangPrintf(stdout
,
211 " **FAIL** Unable to open PPD file - %s\n"),
216 status
= ERROR_PPD_FORMAT
;
220 _cupsLangPrintf(stdout
,
222 " **FAIL** Unable to open PPD file - "
224 ppdErrorString(error
), line
);
228 case PPD_MISSING_PPDADOBE4
:
229 _cupsLangPuts(stdout
,
230 _(" REF: Page 42, section 5.2.\n"));
232 case PPD_MISSING_VALUE
:
233 _cupsLangPuts(stdout
,
234 _(" REF: Page 20, section 3.4.\n"));
236 case PPD_BAD_OPEN_GROUP
:
237 case PPD_NESTED_OPEN_GROUP
:
238 _cupsLangPuts(stdout
,
239 _(" REF: Pages 45-46, section 5.2.\n"));
241 case PPD_BAD_OPEN_UI
:
242 case PPD_NESTED_OPEN_UI
:
243 _cupsLangPuts(stdout
,
244 _(" REF: Pages 42-45, section 5.2.\n"));
246 case PPD_BAD_ORDER_DEPENDENCY
:
247 _cupsLangPuts(stdout
,
248 _(" REF: Pages 48-49, section 5.2.\n"));
250 case PPD_BAD_UI_CONSTRAINTS
:
251 _cupsLangPuts(stdout
,
252 _(" REF: Pages 52-54, section 5.2.\n"));
254 case PPD_MISSING_ASTERISK
:
255 _cupsLangPuts(stdout
,
256 _(" REF: Page 15, section 3.2.\n"));
258 case PPD_LINE_TOO_LONG
:
259 _cupsLangPuts(stdout
,
260 _(" REF: Page 15, section 3.1.\n"));
262 case PPD_ILLEGAL_CHARACTER
:
263 _cupsLangPuts(stdout
,
264 _(" REF: Page 15, section 3.1.\n"));
266 case PPD_ILLEGAL_MAIN_KEYWORD
:
267 _cupsLangPuts(stdout
,
268 _(" REF: Pages 16-17, section 3.2.\n"));
270 case PPD_ILLEGAL_OPTION_KEYWORD
:
271 _cupsLangPuts(stdout
,
272 _(" REF: Page 19, section 3.3.\n"));
274 case PPD_ILLEGAL_TRANSLATION
:
275 _cupsLangPuts(stdout
,
276 _(" REF: Page 27, section 3.5.\n"));
282 check_basics(argv
[i
]);
290 * Show the header and then perform basic conformance tests (limited
291 * only by what the CUPS PPD functions actually load...)
298 _cupsLangPuts(stdout
,
299 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
301 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
303 ppdversion
= (int)(10 * atof(attr
->value
) + 0.5);
306 * Look for default keywords with no matching option...
309 for (i
= 0; i
< ppd
->num_attrs
; i
++)
311 attr
= ppd
->attrs
[i
];
313 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
314 !strcmp(attr
->name
, "DefaultFont") ||
315 !strcmp(attr
->name
, "DefaultImageableArea") ||
316 !strcmp(attr
->name
, "DefaultOutputOrder") ||
317 !strcmp(attr
->name
, "DefaultPaperDimension") ||
318 !strcmp(attr
->name
, "DefaultTransfer"))
321 if (!strncmp(attr
->name
, "Default", 7))
323 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) == NULL
)
324 _cupsLangPrintf(stdout
,
325 _(" WARN %s has no corresponding "
328 else if (strcmp(attr
->value
, "Unknown"))
331 * Check that the default option value matches a choice...
334 for (j
= 0; j
< option
->num_choices
; j
++)
335 if (!strcmp(option
->choices
[j
].choice
, attr
->value
))
338 if (j
>= option
->num_choices
)
342 if (!errors
&& !verbose
)
343 _cupsLangPuts(stdout
, _(" FAIL\n"));
345 _cupsLangPrintf(stdout
,
346 _(" **FAIL** %s %s does not exist!\n"),
347 attr
->name
, attr
->value
);
356 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
360 if (!errors
&& !verbose
)
361 _cupsLangPuts(stdout
, _(" FAIL\n"));
363 _cupsLangPuts(stdout
,
364 _(" **FAIL** REQUIRED DefaultImageableArea\n"
365 " REF: Page 102, section 5.15.\n"));
370 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
371 strcmp(attr
->value
, "Unknown"))
375 if (!errors
&& !verbose
)
376 _cupsLangPuts(stdout
, _(" FAIL\n"));
378 _cupsLangPrintf(stdout
,
379 _(" **FAIL** BAD DefaultImageableArea %s!\n"
380 " REF: Page 102, section 5.15.\n"),
389 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
392 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
396 if (!errors
&& !verbose
)
397 _cupsLangPuts(stdout
, _(" FAIL\n"));
399 _cupsLangPuts(stdout
,
400 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
401 " REF: Page 103, section 5.15.\n"));
406 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
407 strcmp(attr
->value
, "Unknown"))
411 if (!errors
&& !verbose
)
412 _cupsLangPuts(stdout
, _(" FAIL\n"));
414 _cupsLangPrintf(stdout
,
415 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
416 " REF: Page 103, section 5.15.\n"),
422 else if (verbose
> 0)
423 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
425 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
426 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
429 * Verify that we have a default choice...
432 if (option
->defchoice
[0])
434 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
435 strcmp(option
->defchoice
, "Unknown"))
439 if (!errors
&& !verbose
)
440 _cupsLangPuts(stdout
, _(" FAIL\n"));
442 _cupsLangPrintf(stdout
,
443 _(" **FAIL** BAD Default%s %s\n"
444 " REF: Page 40, section 4.5.\n"),
445 option
->keyword
, option
->defchoice
);
450 else if (verbose
> 0)
451 _cupsLangPrintf(stdout
,
452 _(" PASS Default%s\n"),
459 if (!errors
&& !verbose
)
460 _cupsLangPuts(stdout
, _(" FAIL\n"));
462 _cupsLangPrintf(stdout
,
463 _(" **FAIL** REQUIRED Default%s\n"
464 " REF: Page 40, section 4.5.\n"),
472 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
475 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
481 if (!errors
&& !verbose
)
482 _cupsLangPuts(stdout
, _(" FAIL\n"));
484 _cupsLangPuts(stdout
,
485 _(" **FAIL** REQUIRED FileVersion\n"
486 " REF: Page 56, section 5.3.\n"));
492 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
495 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
501 if (!errors
&& !verbose
)
502 _cupsLangPuts(stdout
, _(" FAIL\n"));
504 _cupsLangPuts(stdout
,
505 _(" **FAIL** REQUIRED FormatVersion\n"
506 " REF: Page 56, section 5.3.\n"));
512 if (ppd
->lang_encoding
!= NULL
)
515 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
517 else if (ppdversion
> 40)
521 if (!errors
&& !verbose
)
522 _cupsLangPuts(stdout
, _(" FAIL\n"));
524 _cupsLangPuts(stdout
,
525 _(" **FAIL** REQUIRED LanguageEncoding\n"
526 " REF: Pages 56-57, section 5.3.\n"));
532 if (ppd
->lang_version
!= NULL
)
535 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
541 if (!errors
&& !verbose
)
542 _cupsLangPuts(stdout
, _(" FAIL\n"));
544 _cupsLangPuts(stdout
,
545 _(" **FAIL** REQUIRED LanguageVersion\n"
546 " REF: Pages 57-58, section 5.3.\n"));
552 if (ppd
->manufacturer
!= NULL
)
554 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
555 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
559 if (!errors
&& !verbose
)
560 _cupsLangPuts(stdout
, _(" FAIL\n"));
562 _cupsLangPuts(stdout
,
563 _(" **FAIL** BAD Manufacturer (should be "
565 " REF: Page 211, table D.1.\n"));
570 else if (verbose
> 0)
571 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
573 else if (ppdversion
>= 43)
577 if (!errors
&& !verbose
)
578 _cupsLangPuts(stdout
, _(" FAIL\n"));
580 _cupsLangPuts(stdout
,
581 _(" **FAIL** REQUIRED Manufacturer\n"
582 " REF: Pages 58-59, section 5.3.\n"));
588 if (ppd
->modelname
!= NULL
)
590 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
591 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
598 if (!errors
&& !verbose
)
599 _cupsLangPuts(stdout
, _(" FAIL\n"));
601 _cupsLangPrintf(stdout
,
602 _(" **FAIL** BAD ModelName - \"%c\" not "
603 "allowed in string.\n"
604 " REF: Pages 59-60, section 5.3.\n"),
610 else if (verbose
> 0)
611 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
617 if (!errors
&& !verbose
)
618 _cupsLangPuts(stdout
, _(" FAIL\n"));
620 _cupsLangPuts(stdout
,
621 _(" **FAIL** REQUIRED ModelName\n"
622 " REF: Pages 59-60, section 5.3.\n"));
628 if (ppd
->nickname
!= NULL
)
631 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
637 if (!errors
&& !verbose
)
638 _cupsLangPuts(stdout
, _(" FAIL\n"));
640 _cupsLangPuts(stdout
,
641 _(" **FAIL** REQUIRED NickName\n"
642 " REF: Page 60, section 5.3.\n"));
648 if (ppdFindOption(ppd
, "PageSize") != NULL
)
651 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
657 if (!errors
&& !verbose
)
658 _cupsLangPuts(stdout
, _(" FAIL\n"));
660 _cupsLangPuts(stdout
,
661 _(" **FAIL** REQUIRED PageSize\n"
662 " REF: Pages 99-100, section 5.14.\n"));
668 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
671 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
677 if (!errors
&& !verbose
)
678 _cupsLangPuts(stdout
, _(" FAIL\n"));
680 _cupsLangPuts(stdout
,
681 _(" **FAIL** REQUIRED PageRegion\n"
682 " REF: Page 100, section 5.14.\n"));
688 if (ppd
->pcfilename
!= NULL
)
691 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
697 if (!errors
&& !verbose
)
698 _cupsLangPuts(stdout
, _(" FAIL\n"));
700 _cupsLangPuts(stdout
,
701 _(" **FAIL** REQUIRED PCFileName\n"
702 " REF: Pages 61-62, section 5.3.\n"));
708 if (ppd
->product
!= NULL
)
710 if (ppd
->product
[0] != '(' ||
711 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
715 if (!errors
&& !verbose
)
716 _cupsLangPuts(stdout
, _(" FAIL\n"));
718 _cupsLangPuts(stdout
,
719 _(" **FAIL** BAD Product - not \"(string)\".\n"
720 " REF: Page 62, section 5.3.\n"));
725 else if (verbose
> 0)
726 _cupsLangPuts(stdout
, _(" PASS Product\n"));
732 if (!errors
&& !verbose
)
733 _cupsLangPuts(stdout
, _(" FAIL\n"));
735 _cupsLangPuts(stdout
,
736 _(" **FAIL** REQUIRED Product\n"
737 " REF: Page 62, section 5.3.\n"));
743 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
746 char junkstr
[255]; /* Temp string */
747 int junkint
; /* Temp integer */
750 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
754 if (!errors
&& !verbose
)
755 _cupsLangPuts(stdout
, _(" FAIL\n"));
757 _cupsLangPuts(stdout
,
758 _(" **FAIL** BAD PSVersion - not \"(string) "
760 " REF: Pages 62-64, section 5.3.\n"));
765 else if (verbose
> 0)
766 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
772 if (!errors
&& !verbose
)
773 _cupsLangPuts(stdout
, _(" FAIL\n"));
775 _cupsLangPuts(stdout
,
776 _(" **FAIL** REQUIRED PSVersion\n"
777 " REF: Pages 62-64, section 5.3.\n"));
783 if (ppd
->shortnickname
!= NULL
)
785 if (strlen(ppd
->shortnickname
) > 31)
789 if (!errors
&& !verbose
)
790 _cupsLangPuts(stdout
, _(" FAIL\n"));
792 _cupsLangPuts(stdout
,
793 _(" **FAIL** BAD ShortNickName - longer "
795 " REF: Pages 64-65, section 5.3.\n"));
800 else if (verbose
> 0)
801 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
803 else if (ppdversion
>= 43)
807 if (!errors
&& !verbose
)
808 _cupsLangPuts(stdout
, _(" FAIL\n"));
810 _cupsLangPuts(stdout
,
811 _(" **FAIL** REQUIRED ShortNickName\n"
812 " REF: Page 64-65, section 5.3.\n"));
818 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
819 strstr(ppd
->patches
, "*End"))
823 if (!errors
&& !verbose
)
824 _cupsLangPuts(stdout
, _(" FAIL\n"));
826 _cupsLangPuts(stdout
,
827 _(" **FAIL** BAD JobPatchFile attribute in file\n"
828 " REF: Page 24, section 3.4.\n"));
835 * Check for page sizes without the corresponding ImageableArea or
836 * PaperDimension values...
839 if (ppd
->num_sizes
== 0)
843 if (!errors
&& !verbose
)
844 _cupsLangPuts(stdout
, _(" FAIL\n"));
846 _cupsLangPuts(stdout
,
847 _(" **FAIL** REQUIRED PageSize\n"
848 " REF: Page 41, section 5.\n"
849 " REF: Page 99, section 5.14.\n"));
856 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
859 * Don't check custom size...
862 if (!strcmp(size
->name
, "Custom"))
866 * Check for ImageableArea...
869 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
870 size
->right
== 0.0 && size
->top
== 0.0)
874 if (!errors
&& !verbose
)
875 _cupsLangPuts(stdout
, _(" FAIL\n"));
877 _cupsLangPrintf(stdout
,
878 _(" **FAIL** REQUIRED ImageableArea for "
880 " REF: Page 41, section 5.\n"
881 " REF: Page 102, section 5.15.\n"),
889 * Check for PaperDimension...
892 if (size
->width
== 0.0 && size
->length
== 0.0)
896 if (!errors
&& !verbose
)
897 _cupsLangPuts(stdout
, _(" FAIL\n"));
899 _cupsLangPrintf(stdout
,
900 _(" **FAIL** REQUIRED PaperDimension "
902 " REF: Page 41, section 5.\n"
903 " REF: Page 103, section 5.15.\n"),
913 * Check for valid Resolution, JCLResolution, or SetResolution values...
916 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
917 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
918 option
= ppdFindOption(ppd
, "SetResolution");
922 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
925 * Verify that all resolution options are of the form NNNdpi
929 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
930 if (ptr
> choice
->choice
&& xdpi
> 0)
933 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
940 if (xdpi
<= 0 || ydpi
<= 0 || strcmp(ptr
, "dpi"))
944 if (!errors
&& !verbose
)
945 _cupsLangPuts(stdout
, _(" FAIL\n"));
947 _cupsLangPrintf(stdout
,
948 _(" **FAIL** Bad %s choice %s!\n"
949 " REF: Page 84, section 5.9\n"),
950 option
->keyword
, choice
->choice
);
959 * Check for a duplex option, and for standard values...
962 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
963 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
964 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
965 option
= ppdFindOption(ppd
, "KD03Duplex");
969 if (ppdFindChoice(option
, "None") == NULL
)
973 if (!errors
&& !verbose
)
974 _cupsLangPuts(stdout
, _(" FAIL\n"));
976 _cupsLangPrintf(stdout
,
977 _(" **FAIL** REQUIRED %s does not define "
979 " REF: Page 122, section 5.17\n"),
986 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
987 if (strcmp(choice
->choice
, "None") &&
988 strcmp(choice
->choice
, "DuplexNoTumble") &&
989 strcmp(choice
->choice
, "DuplexTumble") &&
990 strcmp(choice
->choice
, "SimplexTumble"))
994 if (!errors
&& !verbose
)
995 _cupsLangPuts(stdout
, _(" FAIL\n"));
997 _cupsLangPrintf(stdout
,
998 _(" **FAIL** Bad %s choice %s!\n"
999 " REF: Page 122, section 5.17\n"),
1000 option
->keyword
, choice
->choice
);
1007 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1011 * This file contains localizations, check them...
1014 char *languages
, /* Copy of attribute value */
1015 *langstart
, /* Start of current language */
1016 *langptr
, /* Pointer into languages */
1017 keyword
[PPD_MAX_NAME
]; /* Localization keyword */
1020 languages
= strdup(attr
->value
);
1021 for (langptr
= languages
; *langptr
;)
1024 * Skip leading whitespace...
1027 while (isspace(*langptr
& 255))
1034 * Find the end of this language name...
1037 for (langstart
= langptr
;
1038 *langptr
&& !isspace(*langptr
& 255);
1044 j
= strlen(langstart
);
1045 if (j
!= 2 && j
!= 5)
1049 if (!errors
&& !verbose
)
1050 _cupsLangPuts(stdout
, _(" FAIL\n"));
1052 _cupsLangPrintf(stdout
,
1053 _(" **FAIL** Bad language \"%s\"!\n"),
1062 * Loop through all options and choices...
1065 for (option
= ppdFirstOption(ppd
);
1067 option
= ppdNextOption(ppd
))
1069 snprintf(keyword
, sizeof(keyword
), "%s.Translation", langstart
);
1070 if (!ppdFindAttr(ppd
, keyword
, option
->keyword
))
1074 if (!errors
&& !verbose
)
1075 _cupsLangPuts(stdout
, _(" FAIL\n"));
1077 _cupsLangPrintf(stdout
,
1078 _(" **FAIL** Missing \"%s\" translation "
1079 "string for option %s!\n"),
1080 langstart
, option
->keyword
);
1086 for (ptr
= option
->text
; *ptr
; ptr
++)
1094 if (!errors
&& !verbose
)
1095 _cupsLangPuts(stdout
, _(" FAIL\n"));
1097 _cupsLangPrintf(stdout
,
1098 _(" **FAIL** Default translation "
1099 "string for option %s contains 8-bit "
1107 snprintf(keyword
, sizeof(keyword
), "%s.%s", langstart
,
1109 for (j
= 0; j
< option
->num_choices
; j
++)
1111 if (!ppdFindAttr(ppd
, keyword
, option
->choices
[j
].choice
))
1115 if (!errors
&& !verbose
)
1116 _cupsLangPuts(stdout
, _(" FAIL\n"));
1118 _cupsLangPrintf(stdout
,
1119 _(" **FAIL** Missing \"%s\" "
1120 "translation string for option %s, "
1122 langstart
, option
->keyword
,
1123 option
->choices
[j
].choice
);
1129 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1137 if (!errors
&& !verbose
)
1138 _cupsLangPuts(stdout
, _(" FAIL\n"));
1140 _cupsLangPrintf(stdout
,
1141 _(" **FAIL** Default translation "
1142 "string for option %s choice %s contains "
1143 "8-bit characters!\n"),
1145 option
->choices
[j
].choice
);
1155 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
1157 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
1159 char super
[16], /* Filter super type */
1160 type
[256], /* Filter type */
1161 program
[256]; /* Filter program */
1162 int cost
; /* Filter cost */
1166 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1171 if (!errors
&& !verbose
)
1172 _cupsLangPuts(stdout
, _(" FAIL\n"));
1174 _cupsLangPrintf(stdout
,
1175 _(" **FAIL** Bad cupsFilter value \"%s\"!\n"),
1176 attr
->value
? attr
->value
: "");
1184 status
= ERROR_CONFORMANCE
;
1186 _cupsLangPuts(stdout
, _(" PASS\n"));
1190 check_basics(argv
[i
]);
1193 strcmp(option
->keyword
, "Duplex") &&
1194 strcmp(option
->keyword
, "JCLDuplex"))
1196 _cupsLangPrintf(stdout
,
1197 _(" WARN Duplex option keyword %s "
1198 "should be named Duplex or JCLDuplex!\n"
1199 " REF: Page 122, section 5.17\n"),
1203 ppdMarkDefaults(ppd
);
1204 if (ppdConflicts(ppd
))
1206 _cupsLangPuts(stdout
,
1207 _(" WARN Default choices conflicting!\n"));
1209 show_conflicts(ppd
);
1212 if (ppdversion
< 43)
1214 _cupsLangPrintf(stdout
,
1215 _(" WARN Obsolete PPD version %.1f!\n"
1216 " REF: Page 42, section 5.2.\n"),
1220 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1222 _cupsLangPuts(stdout
,
1223 _(" WARN LanguageEncoding required by PPD "
1225 " REF: Pages 56-57, section 5.3.\n"));
1228 if (!ppd
->manufacturer
&& ppdversion
< 43)
1230 _cupsLangPuts(stdout
,
1231 _(" WARN Manufacturer required by PPD "
1233 " REF: Pages 58-59, section 5.3.\n"));
1237 * Treat a PCFileName attribute longer than 12 characters as
1238 * a warning and not a hard error...
1241 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1243 _cupsLangPuts(stdout
,
1244 _(" WARN PCFileName longer than 8.3 in "
1245 "violation of PPD spec.\n"
1246 " REF: Pages 61-62, section 5.3.\n"));
1249 if (!ppd
->shortnickname
&& ppdversion
< 43)
1251 _cupsLangPuts(stdout
,
1252 _(" WARN ShortNickName required by PPD "
1254 " REF: Pages 64-65, section 5.3.\n"));
1258 * Check the Protocols line and flag PJL + BCP since TBCP is
1259 * usually used with PJL...
1264 if (strstr(ppd
->protocols
, "PJL") &&
1265 strstr(ppd
->protocols
, "BCP") &&
1266 !strstr(ppd
->protocols
, "TBCP"))
1268 _cupsLangPuts(stdout
,
1269 _(" WARN Protocols contains both PJL "
1270 "and BCP; expected TBCP.\n"
1271 " REF: Pages 78-79, section 5.7.\n"));
1274 if (strstr(ppd
->protocols
, "PJL") &&
1275 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1277 _cupsLangPuts(stdout
,
1278 _(" WARN Protocols contains PJL but JCL "
1279 "attributes are not set.\n"
1280 " REF: Pages 78-79, section 5.7.\n"));
1285 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1286 * which are errors according to the spec but won't cause problems
1287 * with CUPS specifically...
1290 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1291 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1293 len
= strlen(option
->keyword
);
1295 for (m
= 0, group2
= ppd
->groups
;
1296 m
< ppd
->num_groups
;
1298 for (n
= 0, option2
= group2
->options
;
1299 n
< group2
->num_options
;
1301 if (option
!= option2
&&
1302 len
< strlen(option2
->keyword
) &&
1303 !strncmp(option
->keyword
, option2
->keyword
, len
))
1305 _cupsLangPrintf(stdout
,
1306 _(" WARN %s shares a common "
1308 " REF: Page 15, section "
1310 option
->keyword
, option2
->keyword
);
1318 _cupsLangPrintf(stdout
, _(" %d ERROR%s FOUND\n"),
1319 errors
, errors
== 1 ? "" : "S");
1321 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1325 * Then list the options, if "-v" was provided...
1330 _cupsLangPrintf(stdout
,
1332 " language_level = %d\n"
1333 " color_device = %s\n"
1334 " variable_sizes = %s\n"
1335 " landscape = %d\n",
1336 ppd
->language_level
,
1337 ppd
->color_device
? "TRUE" : "FALSE",
1338 ppd
->variable_sizes
? "TRUE" : "FALSE",
1341 switch (ppd
->colorspace
)
1344 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1347 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1350 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1353 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1356 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1360 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1361 ppd
->num_emulations
);
1362 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1363 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1364 j
, ppd
->emulations
[j
].name
);
1366 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1367 ppd
->lang_encoding
);
1368 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1370 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1371 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1372 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1373 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1375 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1376 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1377 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1378 ppd
->shortnickname
);
1379 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1380 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1382 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1383 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1385 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1388 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1390 _cupsLangPrintf(stdout
,
1391 " options[%d] = %s (%s) %s %s %.0f "
1393 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1394 sections
[option
->section
], option
->order
,
1395 option
->num_choices
);
1397 if (!strcmp(option
->keyword
, "PageSize") ||
1398 !strcmp(option
->keyword
, "PageRegion"))
1400 for (m
= option
->num_choices
, choice
= option
->choices
;
1404 size
= ppdPageSize(ppd
, choice
->choice
);
1407 _cupsLangPrintf(stdout
,
1409 choice
->choice
, choice
->text
);
1411 _cupsLangPrintf(stdout
,
1412 " %s (%s) = %.2fx%.2fin "
1413 "(%.1f,%.1f,%.1f,%.1f)",
1414 choice
->choice
, choice
->text
,
1415 size
->width
/ 72.0, size
->length
/ 72.0,
1416 size
->left
/ 72.0, size
->bottom
/ 72.0,
1417 size
->right
/ 72.0, size
->top
/ 72.0);
1419 if (!strcmp(option
->defchoice
, choice
->choice
))
1420 _cupsLangPuts(stdout
, " *\n");
1422 _cupsLangPuts(stdout
, "\n");
1427 for (m
= option
->num_choices
, choice
= option
->choices
;
1431 _cupsLangPrintf(stdout
, " %s (%s)",
1432 choice
->choice
, choice
->text
);
1434 if (!strcmp(option
->defchoice
, choice
->choice
))
1435 _cupsLangPuts(stdout
, " *\n");
1437 _cupsLangPuts(stdout
, "\n");
1443 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1445 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1446 _cupsLangPrintf(stdout
,
1447 " profiles[%d] = %s/%s %.3f %.3f "
1448 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1449 j
, ppd
->profiles
[j
].resolution
,
1450 ppd
->profiles
[j
].media_type
,
1451 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1452 ppd
->profiles
[j
].matrix
[0][0],
1453 ppd
->profiles
[j
].matrix
[0][1],
1454 ppd
->profiles
[j
].matrix
[0][2],
1455 ppd
->profiles
[j
].matrix
[1][0],
1456 ppd
->profiles
[j
].matrix
[1][1],
1457 ppd
->profiles
[j
].matrix
[1][2],
1458 ppd
->profiles
[j
].matrix
[2][0],
1459 ppd
->profiles
[j
].matrix
[2][1],
1460 ppd
->profiles
[j
].matrix
[2][2]);
1462 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1463 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1464 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1467 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1468 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1469 _cupsLangPrintf(stdout
,
1470 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1471 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1472 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1473 ppd
->attrs
[j
]->text
,
1474 ppd
->attrs
[j
]->value
?
1475 ppd
->attrs
[j
]->value
: "(null)");
1489 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1493 check_basics(const char *filename
) /* I - PPD file to check */
1495 cups_file_t
*fp
; /* File pointer */
1496 int ch
; /* Current character */
1497 int col
, /* Current column */
1498 whitespace
; /* Only seen whitespace? */
1499 int eol
; /* Line endings */
1500 int linenum
; /* Line number */
1501 int mixed
; /* Mixed line endings? */
1504 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1513 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1515 if (ch
== '\r' || ch
== '\n')
1519 if (eol
== EOL_NONE
)
1521 else if (eol
!= EOL_LF
)
1524 else if (ch
== '\r')
1526 if (cupsFilePeekChar(fp
) == '\n')
1528 cupsFileGetChar(fp
);
1530 if (eol
== EOL_NONE
)
1535 else if (eol
== EOL_NONE
)
1541 if (col
> 0 && whitespace
)
1542 _cupsLangPrintf(stdout
,
1543 _(" WARN Line %d only contains whitespace!\n"),
1552 if (ch
!= ' ' && ch
!= '\t')
1560 _cupsLangPuts(stdout
,
1561 _(" WARN File contains a mix of CR, LF, and "
1562 "CR LF line endings!\n"));
1564 if (eol
== EOL_CRLF
)
1565 _cupsLangPuts(stdout
,
1566 _(" WARN Non-Windows PPD files should use lines "
1567 "ending with only LF, not CR LF!\n"));
1574 * 'show_conflicts()' - Show option conflicts in a PPD file.
1578 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
1580 int i
, j
; /* Looping variables */
1581 ppd_const_t
*c
; /* Current constraint */
1582 ppd_option_t
*o1
, *o2
; /* Options */
1583 ppd_choice_t
*c1
, *c2
; /* Choices */
1587 * Loop through all of the UI constraints and report any options
1591 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1594 * Grab pointers to the first option...
1597 o1
= ppdFindOption(ppd
, c
->option1
);
1601 else if (c
->choice1
[0] != '\0')
1604 * This constraint maps to a specific choice.
1607 c1
= ppdFindChoice(o1
, c
->choice1
);
1612 * This constraint applies to any choice for this option.
1615 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
1620 !strcasecmp(c1
->choice
, "None") ||
1621 !strcasecmp(c1
->choice
, "Off") ||
1622 !strcasecmp(c1
->choice
, "False"))
1627 * Grab pointers to the second option...
1630 o2
= ppdFindOption(ppd
, c
->option2
);
1634 else if (c
->choice2
[0] != '\0')
1637 * This constraint maps to a specific choice.
1640 c2
= ppdFindChoice(o2
, c
->choice2
);
1645 * This constraint applies to any choice for this option.
1648 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
1653 !strcasecmp(c2
->choice
, "None") ||
1654 !strcasecmp(c2
->choice
, "Off") ||
1655 !strcasecmp(c2
->choice
, "False"))
1660 * If both options are marked then there is a conflict...
1663 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
1664 _cupsLangPrintf(stdout
,
1665 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
1666 " (constraint=\"%s %s %s %s\")\n"),
1667 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
1668 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1674 * 'usage()' - Show program usage...
1680 _cupsLangPuts(stdout
,
1681 _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] "
1682 "[... filenameN.ppd[.gz]]\n"
1683 " program | cupstestppd [-q] [-r] [-v[v]] -\n"));
1690 * End of "$Id: cupstestppd.c 5189 2006-02-27 01:45:57Z mike $".