2 * "$Id: cupstestppd.c 7637 2008-06-11 17:25:36Z mike $"
4 * PPD test program for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
15 * PostScript is a trademark of Adobe Systems, Inc.
17 * This file is subject to the Apple OS-Developed Software exception.
21 * main() - Main entry for test program.
22 * check_basics() - Check for CR LF, mixed line endings, and blank
24 * check_constraints() - Check UIConstraints in the PPD file.
25 * check_defaults() - Check default option keywords in the PPD file.
26 * check_filters() - Check filters in the PPD file.
27 * check_profiles() - Check ICC color profiles in the PPD file.
28 * check_translations() - Check translations in the PPD file.
29 * show_conflicts() - Show option conflicts in a PPD file.
30 * test_raster() - Test PostScript commands for raster printers.
31 * usage() - Show program usage...
32 * valid_utf8() - Check whether a string contains valid UTF-8 text.
36 * Include necessary headers...
39 #include <cups/string.h>
40 #include <cups/cups.h>
41 #include <cups/ppd-private.h>
42 #include <cups/i18n.h>
43 #include <cups/raster.h>
50 * Error warning overrides...
60 WARN_TRANSLATIONS
= 16,
96 static void check_basics(const char *filename
);
97 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
99 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
101 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
102 int verbose
, int warn
);
103 static int check_profiles(ppd_file_t
*ppd
, const char *root
, int errors
,
104 int verbose
, int warn
);
105 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,\
107 static void show_conflicts(ppd_file_t
*ppd
);
108 static int test_raster(ppd_file_t
*ppd
, int verbose
);
109 static void usage(void);
110 static int valid_utf8(const char *s
);
114 * 'main()' - Main entry for test program.
117 int /* O - Exit status */
118 main(int argc
, /* I - Number of command-line args */
119 char *argv
[]) /* I - Command-line arguments */
121 int i
, j
, k
, m
, n
; /* Looping vars */
122 int len
; /* Length of option name */
123 char *opt
; /* Option character */
124 const char *ptr
; /* Pointer into string */
125 int files
; /* Number of files */
126 int verbose
; /* Want verbose output? */
127 int warn
; /* Which errors to just warn about */
128 int status
; /* Exit status */
129 int errors
; /* Number of conformance errors */
130 int ppdversion
; /* PPD spec version in PPD file */
131 ppd_status_t error
; /* Status of ppdOpen*() */
132 int line
; /* Line number for error */
133 char *root
; /* Root directory */
134 int xdpi
, /* X resolution */
135 ydpi
; /* Y resolution */
136 ppd_file_t
*ppd
; /* PPD file record */
137 ppd_attr_t
*attr
; /* PPD attribute */
138 ppd_size_t
*size
; /* Size record */
139 ppd_group_t
*group
; /* UI group */
140 ppd_option_t
*option
; /* Standard UI option */
141 ppd_group_t
*group2
; /* UI group */
142 ppd_option_t
*option2
; /* Standard UI option */
143 ppd_choice_t
*choice
; /* Standard UI option choice */
144 struct lconv
*loc
; /* Locale data */
145 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
146 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
147 "JCL", "PAGE", "PROLOG" };
150 _cupsSetLocale(argv
);
154 * Display PPD files for each file listed on the command-line...
157 ppdSetConformance(PPD_CONFORM_STRICT
);
166 for (i
= 1; i
< argc
; i
++)
167 if (argv
[i
][0] == '-' && argv
[i
][1])
169 for (opt
= argv
[i
] + 1; *opt
; opt
++)
172 case 'R' : /* Alternate root directory */
181 case 'W' : /* Turn errors into warnings */
187 if (!strcmp(argv
[i
], "none"))
189 else if (!strcmp(argv
[i
], "constraints"))
190 warn
|= WARN_CONSTRAINTS
;
191 else if (!strcmp(argv
[i
], "defaults"))
192 warn
|= WARN_DEFAULTS
;
193 else if (!strcmp(argv
[i
], "filters"))
194 warn
|= WARN_FILTERS
;
195 else if (!strcmp(argv
[i
], "profiles"))
196 warn
|= WARN_PROFILES
;
197 else if (!strcmp(argv
[i
], "translations"))
198 warn
|= WARN_TRANSLATIONS
;
199 else if (!strcmp(argv
[i
], "all"))
205 case 'q' : /* Quiet mode */
208 _cupsLangPuts(stderr
,
209 _("cupstestppd: The -q option is incompatible "
210 "with the -v option.\n"));
217 case 'r' : /* Relaxed mode */
218 ppdSetConformance(PPD_CONFORM_RELAXED
);
221 case 'v' : /* Verbose mode */
224 _cupsLangPuts(stderr
,
225 _("cupstestppd: The -v option is incompatible "
226 "with the -q option.\n"));
241 * Open the PPD file...
244 if (files
&& verbose
>= 0)
245 _cupsLangPuts(stdout
, "\n");
249 if (argv
[i
][0] == '-')
255 ppd
= ppdOpen(stdin
);
258 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
263 * Read from a file...
267 printf("%s:", argv
[i
]);
269 ppd
= ppdOpenFile(argv
[i
]);
274 error
= ppdLastError(&line
);
276 if (error
<= PPD_ALLOC_ERROR
)
278 status
= ERROR_FILE_OPEN
;
281 _cupsLangPrintf(stdout
,
283 " **FAIL** Unable to open PPD file - %s\n"),
288 status
= ERROR_PPD_FORMAT
;
292 _cupsLangPrintf(stdout
,
294 " **FAIL** Unable to open PPD file - "
296 ppdErrorString(error
), line
);
300 case PPD_MISSING_PPDADOBE4
:
301 _cupsLangPuts(stdout
,
302 _(" REF: Page 42, section 5.2.\n"));
304 case PPD_MISSING_VALUE
:
305 _cupsLangPuts(stdout
,
306 _(" REF: Page 20, section 3.4.\n"));
308 case PPD_BAD_OPEN_GROUP
:
309 case PPD_NESTED_OPEN_GROUP
:
310 _cupsLangPuts(stdout
,
311 _(" REF: Pages 45-46, section 5.2.\n"));
313 case PPD_BAD_OPEN_UI
:
314 case PPD_NESTED_OPEN_UI
:
315 _cupsLangPuts(stdout
,
316 _(" REF: Pages 42-45, section 5.2.\n"));
318 case PPD_BAD_ORDER_DEPENDENCY
:
319 _cupsLangPuts(stdout
,
320 _(" REF: Pages 48-49, section 5.2.\n"));
322 case PPD_BAD_UI_CONSTRAINTS
:
323 _cupsLangPuts(stdout
,
324 _(" REF: Pages 52-54, section 5.2.\n"));
326 case PPD_MISSING_ASTERISK
:
327 _cupsLangPuts(stdout
,
328 _(" REF: Page 15, section 3.2.\n"));
330 case PPD_LINE_TOO_LONG
:
331 _cupsLangPuts(stdout
,
332 _(" REF: Page 15, section 3.1.\n"));
334 case PPD_ILLEGAL_CHARACTER
:
335 _cupsLangPuts(stdout
,
336 _(" REF: Page 15, section 3.1.\n"));
338 case PPD_ILLEGAL_MAIN_KEYWORD
:
339 _cupsLangPuts(stdout
,
340 _(" REF: Pages 16-17, section 3.2.\n"));
342 case PPD_ILLEGAL_OPTION_KEYWORD
:
343 _cupsLangPuts(stdout
,
344 _(" REF: Page 19, section 3.3.\n"));
346 case PPD_ILLEGAL_TRANSLATION
:
347 _cupsLangPuts(stdout
,
348 _(" REF: Page 27, section 3.5.\n"));
354 check_basics(argv
[i
]);
362 * Show the header and then perform basic conformance tests (limited
363 * only by what the CUPS PPD functions actually load...)
370 _cupsLangPuts(stdout
,
371 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
373 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
375 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
377 for (j
= 0; j
< ppd
->num_filters
; j
++)
378 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
380 if (!test_raster(ppd
, verbose
))
386 * Look for default keywords with no matching option...
389 if (!(warn
& WARN_DEFAULTS
))
390 errors
= check_defaults(ppd
, errors
, verbose
, 0);
392 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
396 if (!errors
&& !verbose
)
397 _cupsLangPuts(stdout
, _(" FAIL\n"));
399 _cupsLangPuts(stdout
,
400 _(" **FAIL** REQUIRED DefaultImageableArea\n"
401 " REF: Page 102, 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 DefaultImageableArea %s!\n"
416 " REF: Page 102, section 5.15.\n"),
425 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
428 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
432 if (!errors
&& !verbose
)
433 _cupsLangPuts(stdout
, _(" FAIL\n"));
435 _cupsLangPuts(stdout
,
436 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
437 " REF: Page 103, section 5.15.\n"));
442 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
443 strcmp(attr
->value
, "Unknown"))
447 if (!errors
&& !verbose
)
448 _cupsLangPuts(stdout
, _(" FAIL\n"));
450 _cupsLangPrintf(stdout
,
451 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
452 " REF: Page 103, section 5.15.\n"),
458 else if (verbose
> 0)
459 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
461 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
462 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
465 * Verify that we have a default choice...
468 if (option
->defchoice
[0])
470 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
471 strcmp(option
->defchoice
, "Unknown"))
475 if (!errors
&& !verbose
)
476 _cupsLangPuts(stdout
, _(" FAIL\n"));
478 _cupsLangPrintf(stdout
,
479 _(" **FAIL** BAD Default%s %s\n"
480 " REF: Page 40, section 4.5.\n"),
481 option
->keyword
, option
->defchoice
);
486 else if (verbose
> 0)
487 _cupsLangPrintf(stdout
,
488 _(" PASS Default%s\n"),
495 if (!errors
&& !verbose
)
496 _cupsLangPuts(stdout
, _(" FAIL\n"));
498 _cupsLangPrintf(stdout
,
499 _(" **FAIL** REQUIRED Default%s\n"
500 " REF: Page 40, section 4.5.\n"),
508 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
511 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
517 if (!errors
&& !verbose
)
518 _cupsLangPuts(stdout
, _(" FAIL\n"));
520 _cupsLangPuts(stdout
,
521 _(" **FAIL** REQUIRED FileVersion\n"
522 " REF: Page 56, section 5.3.\n"));
528 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
531 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
537 if (!errors
&& !verbose
)
538 _cupsLangPuts(stdout
, _(" FAIL\n"));
540 _cupsLangPuts(stdout
,
541 _(" **FAIL** REQUIRED FormatVersion\n"
542 " REF: Page 56, section 5.3.\n"));
548 if (ppd
->lang_encoding
!= NULL
)
551 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
553 else if (ppdversion
> 40)
557 if (!errors
&& !verbose
)
558 _cupsLangPuts(stdout
, _(" FAIL\n"));
560 _cupsLangPuts(stdout
,
561 _(" **FAIL** REQUIRED LanguageEncoding\n"
562 " REF: Pages 56-57, section 5.3.\n"));
568 if (ppd
->lang_version
!= NULL
)
571 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
577 if (!errors
&& !verbose
)
578 _cupsLangPuts(stdout
, _(" FAIL\n"));
580 _cupsLangPuts(stdout
,
581 _(" **FAIL** REQUIRED LanguageVersion\n"
582 " REF: Pages 57-58, section 5.3.\n"));
588 if (ppd
->manufacturer
!= NULL
)
590 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
591 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
595 if (!errors
&& !verbose
)
596 _cupsLangPuts(stdout
, _(" FAIL\n"));
598 _cupsLangPuts(stdout
,
599 _(" **FAIL** BAD Manufacturer (should be "
601 " REF: Page 211, table D.1.\n"));
606 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
607 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
611 if (!errors
&& !verbose
)
612 _cupsLangPuts(stdout
, _(" FAIL\n"));
614 _cupsLangPuts(stdout
,
615 _(" **FAIL** BAD Manufacturer (should be "
617 " REF: Page 211, table D.1.\n"));
622 else if (verbose
> 0)
623 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
625 else if (ppdversion
>= 43)
629 if (!errors
&& !verbose
)
630 _cupsLangPuts(stdout
, _(" FAIL\n"));
632 _cupsLangPuts(stdout
,
633 _(" **FAIL** REQUIRED Manufacturer\n"
634 " REF: Pages 58-59, section 5.3.\n"));
640 if (ppd
->modelname
!= NULL
)
642 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
643 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
650 if (!errors
&& !verbose
)
651 _cupsLangPuts(stdout
, _(" FAIL\n"));
653 _cupsLangPrintf(stdout
,
654 _(" **FAIL** BAD ModelName - \"%c\" not "
655 "allowed in string.\n"
656 " REF: Pages 59-60, section 5.3.\n"),
662 else if (verbose
> 0)
663 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
669 if (!errors
&& !verbose
)
670 _cupsLangPuts(stdout
, _(" FAIL\n"));
672 _cupsLangPuts(stdout
,
673 _(" **FAIL** REQUIRED ModelName\n"
674 " REF: Pages 59-60, section 5.3.\n"));
680 if (ppd
->nickname
!= NULL
)
683 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
689 if (!errors
&& !verbose
)
690 _cupsLangPuts(stdout
, _(" FAIL\n"));
692 _cupsLangPuts(stdout
,
693 _(" **FAIL** REQUIRED NickName\n"
694 " REF: Page 60, section 5.3.\n"));
700 if (ppdFindOption(ppd
, "PageSize") != NULL
)
703 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
709 if (!errors
&& !verbose
)
710 _cupsLangPuts(stdout
, _(" FAIL\n"));
712 _cupsLangPuts(stdout
,
713 _(" **FAIL** REQUIRED PageSize\n"
714 " REF: Pages 99-100, section 5.14.\n"));
720 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
723 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
729 if (!errors
&& !verbose
)
730 _cupsLangPuts(stdout
, _(" FAIL\n"));
732 _cupsLangPuts(stdout
,
733 _(" **FAIL** REQUIRED PageRegion\n"
734 " REF: Page 100, section 5.14.\n"));
740 if (ppd
->pcfilename
!= NULL
)
743 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
749 if (!errors
&& !verbose
)
750 _cupsLangPuts(stdout
, _(" FAIL\n"));
752 _cupsLangPuts(stdout
,
753 _(" **FAIL** REQUIRED PCFileName\n"
754 " REF: Pages 61-62, section 5.3.\n"));
760 if (ppd
->product
!= NULL
)
762 if (ppd
->product
[0] != '(' ||
763 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
767 if (!errors
&& !verbose
)
768 _cupsLangPuts(stdout
, _(" FAIL\n"));
770 _cupsLangPuts(stdout
,
771 _(" **FAIL** BAD Product - not \"(string)\".\n"
772 " REF: Page 62, section 5.3.\n"));
777 else if (verbose
> 0)
778 _cupsLangPuts(stdout
, _(" PASS Product\n"));
784 if (!errors
&& !verbose
)
785 _cupsLangPuts(stdout
, _(" FAIL\n"));
787 _cupsLangPuts(stdout
,
788 _(" **FAIL** REQUIRED Product\n"
789 " REF: Page 62, section 5.3.\n"));
795 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
798 char junkstr
[255]; /* Temp string */
799 int junkint
; /* Temp integer */
802 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
806 if (!errors
&& !verbose
)
807 _cupsLangPuts(stdout
, _(" FAIL\n"));
809 _cupsLangPuts(stdout
,
810 _(" **FAIL** BAD PSVersion - not \"(string) "
812 " REF: Pages 62-64, section 5.3.\n"));
817 else if (verbose
> 0)
818 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
824 if (!errors
&& !verbose
)
825 _cupsLangPuts(stdout
, _(" FAIL\n"));
827 _cupsLangPuts(stdout
,
828 _(" **FAIL** REQUIRED PSVersion\n"
829 " REF: Pages 62-64, section 5.3.\n"));
835 if (ppd
->shortnickname
!= NULL
)
837 if (strlen(ppd
->shortnickname
) > 31)
841 if (!errors
&& !verbose
)
842 _cupsLangPuts(stdout
, _(" FAIL\n"));
844 _cupsLangPuts(stdout
,
845 _(" **FAIL** BAD ShortNickName - longer "
847 " REF: Pages 64-65, section 5.3.\n"));
852 else if (verbose
> 0)
853 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
855 else if (ppdversion
>= 43)
859 if (!errors
&& !verbose
)
860 _cupsLangPuts(stdout
, _(" FAIL\n"));
862 _cupsLangPuts(stdout
,
863 _(" **FAIL** REQUIRED ShortNickName\n"
864 " REF: Page 64-65, section 5.3.\n"));
870 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
871 strstr(ppd
->patches
, "*End"))
875 if (!errors
&& !verbose
)
876 _cupsLangPuts(stdout
, _(" FAIL\n"));
878 _cupsLangPuts(stdout
,
879 _(" **FAIL** BAD JobPatchFile attribute in file\n"
880 " REF: Page 24, section 3.4.\n"));
887 * Check for page sizes without the corresponding ImageableArea or
888 * PaperDimension values...
891 if (ppd
->num_sizes
== 0)
895 if (!errors
&& !verbose
)
896 _cupsLangPuts(stdout
, _(" FAIL\n"));
898 _cupsLangPuts(stdout
,
899 _(" **FAIL** REQUIRED PageSize\n"
900 " REF: Page 41, section 5.\n"
901 " REF: Page 99, section 5.14.\n"));
908 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
911 * Don't check custom size...
914 if (!strcmp(size
->name
, "Custom"))
918 * Check for ImageableArea...
921 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
922 size
->right
== 0.0 && size
->top
== 0.0)
926 if (!errors
&& !verbose
)
927 _cupsLangPuts(stdout
, _(" FAIL\n"));
929 _cupsLangPrintf(stdout
,
930 _(" **FAIL** REQUIRED ImageableArea for "
932 " REF: Page 41, section 5.\n"
933 " REF: Page 102, section 5.15.\n"),
941 * Check for PaperDimension...
944 if (size
->width
== 0.0 && size
->length
== 0.0)
948 if (!errors
&& !verbose
)
949 _cupsLangPuts(stdout
, _(" FAIL\n"));
951 _cupsLangPrintf(stdout
,
952 _(" **FAIL** REQUIRED PaperDimension "
954 " REF: Page 41, section 5.\n"
955 " REF: Page 103, section 5.15.\n"),
965 * Check for valid Resolution, JCLResolution, or SetResolution values...
968 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
969 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
970 option
= ppdFindOption(ppd
, "SetResolution");
974 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
977 * Verify that all resolution options are of the form NNNdpi
981 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
982 if (ptr
> choice
->choice
&& xdpi
> 0)
985 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
992 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
997 if (!errors
&& !verbose
)
998 _cupsLangPuts(stdout
, _(" FAIL\n"));
1000 _cupsLangPrintf(stdout
,
1001 _(" **FAIL** Bad %s choice %s!\n"
1002 " REF: Page 84, section 5.9\n"),
1003 option
->keyword
, choice
->choice
);
1012 * Check for a duplex option, and for standard values...
1015 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
1016 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1017 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1018 option
= ppdFindOption(ppd
, "KD03Duplex");
1022 if (ppdFindChoice(option
, "None") == NULL
)
1026 if (!errors
&& !verbose
)
1027 _cupsLangPuts(stdout
, _(" FAIL\n"));
1029 _cupsLangPrintf(stdout
,
1030 _(" **FAIL** REQUIRED %s does not define "
1032 " REF: Page 122, section 5.17\n"),
1039 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
1040 if (strcmp(choice
->choice
, "None") &&
1041 strcmp(choice
->choice
, "DuplexNoTumble") &&
1042 strcmp(choice
->choice
, "DuplexTumble") &&
1043 strcmp(choice
->choice
, "SimplexTumble"))
1047 if (!errors
&& !verbose
)
1048 _cupsLangPuts(stdout
, _(" FAIL\n"));
1050 _cupsLangPrintf(stdout
,
1051 _(" **FAIL** Bad %s choice %s!\n"
1052 " REF: Page 122, section 5.17\n"),
1053 option
->keyword
, choice
->choice
);
1060 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1061 strcmp(attr
->name
, "1284DeviceID"))
1065 if (!errors
&& !verbose
)
1066 _cupsLangPuts(stdout
, _(" FAIL\n"));
1068 _cupsLangPrintf(stdout
,
1069 _(" **FAIL** %s must be 1284DeviceID!\n"
1070 " REF: Page 72, section 5.5\n"),
1077 if (!(warn
& WARN_CONSTRAINTS
))
1078 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1080 if (!(warn
& WARN_FILTERS
))
1081 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1083 if (!(warn
& WARN_PROFILES
))
1084 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1086 if (!(warn
& WARN_TRANSLATIONS
))
1087 errors
= check_translations(ppd
, errors
, verbose
, 0);
1089 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1093 * This file contains localizations, check for conformance of the
1094 * base translation...
1097 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1099 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1101 if (!errors
&& !verbose
)
1102 _cupsLangPuts(stdout
, _(" FAIL\n"));
1105 _cupsLangPrintf(stdout
,
1106 _(" **FAIL** Bad LanguageEncoding %s - "
1107 "must be ISOLatin1!\n"),
1108 attr
->value
? attr
->value
: "(null)");
1113 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1115 if (!errors
&& !verbose
)
1116 _cupsLangPuts(stdout
, _(" FAIL\n"));
1119 _cupsLangPrintf(stdout
,
1120 _(" **FAIL** Bad LanguageVersion %s - "
1121 "must be English!\n"),
1122 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1128 * Loop through all options and choices...
1131 for (option
= ppdFirstOption(ppd
);
1133 option
= ppdNextOption(ppd
))
1136 * Check for special characters outside A0 to BF, F7, or F8
1137 * that are used for languages other than English.
1140 for (ptr
= option
->text
; *ptr
; ptr
++)
1141 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1142 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1147 if (!errors
&& !verbose
)
1148 _cupsLangPuts(stdout
, _(" FAIL\n"));
1151 _cupsLangPrintf(stdout
,
1152 _(" **FAIL** Default translation "
1153 "string for option %s contains 8-bit "
1160 for (j
= 0; j
< option
->num_choices
; j
++)
1163 * Check for special characters outside A0 to BF, F7, or F8
1164 * that are used for languages other than English.
1167 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1168 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1169 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1174 if (!errors
&& !verbose
)
1175 _cupsLangPuts(stdout
, _(" FAIL\n"));
1178 _cupsLangPrintf(stdout
,
1179 _(" **FAIL** Default translation "
1180 "string for option %s choice %s contains "
1181 "8-bit characters!\n"),
1183 option
->choices
[j
].choice
);
1193 * Final pass/fail notification...
1197 status
= ERROR_CONFORMANCE
;
1199 _cupsLangPuts(stdout
, _(" PASS\n"));
1203 check_basics(argv
[i
]);
1205 if (warn
& WARN_CONSTRAINTS
)
1206 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1208 if (warn
& WARN_DEFAULTS
)
1209 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1211 if (warn
& WARN_PROFILES
)
1212 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1214 if (warn
& WARN_FILTERS
)
1215 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1217 if (warn
& WARN_TRANSLATIONS
)
1218 errors
= check_translations(ppd
, errors
, verbose
, 1);
1221 * Look for default keywords with no corresponding option...
1224 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1226 attr
= ppd
->attrs
[j
];
1228 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1229 !strcmp(attr
->name
, "DefaultColorSep") ||
1230 !strcmp(attr
->name
, "DefaultFont") ||
1231 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1232 !strcmp(attr
->name
, "DefaultImageableArea") ||
1233 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1234 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1235 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1236 !strcmp(attr
->name
, "DefaultResolution") ||
1237 !strcmp(attr
->name
, "DefaultScreenProc") ||
1238 !strcmp(attr
->name
, "DefaultTransfer"))
1241 if (!strncmp(attr
->name
, "Default", 7) &&
1242 !ppdFindOption(ppd
, attr
->name
+ 7))
1243 _cupsLangPrintf(stdout
,
1244 _(" WARN %s has no corresponding "
1250 * Check for old Duplex option names...
1253 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1254 option
= ppdFindOption(ppd
, "KD03Duplex");
1258 _cupsLangPrintf(stdout
,
1259 _(" WARN Duplex option keyword %s "
1260 "should be named Duplex or JCLDuplex!\n"
1261 " REF: Page 122, section 5.17\n"),
1265 ppdMarkDefaults(ppd
);
1266 if (ppdConflicts(ppd
))
1268 _cupsLangPuts(stdout
,
1269 _(" WARN Default choices conflicting!\n"));
1271 show_conflicts(ppd
);
1274 if (ppdversion
< 43)
1276 _cupsLangPrintf(stdout
,
1277 _(" WARN Obsolete PPD version %.1f!\n"
1278 " REF: Page 42, section 5.2.\n"),
1282 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1284 _cupsLangPuts(stdout
,
1285 _(" WARN LanguageEncoding required by PPD "
1287 " REF: Pages 56-57, section 5.3.\n"));
1290 if (!ppd
->manufacturer
&& ppdversion
< 43)
1292 _cupsLangPuts(stdout
,
1293 _(" WARN Manufacturer required by PPD "
1295 " REF: Pages 58-59, section 5.3.\n"));
1299 * Treat a PCFileName attribute longer than 12 characters as
1300 * a warning and not a hard error...
1303 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1305 _cupsLangPuts(stdout
,
1306 _(" WARN PCFileName longer than 8.3 in "
1307 "violation of PPD spec.\n"
1308 " REF: Pages 61-62, section 5.3.\n"));
1311 if (!ppd
->shortnickname
&& ppdversion
< 43)
1313 _cupsLangPuts(stdout
,
1314 _(" WARN ShortNickName required by PPD "
1316 " REF: Pages 64-65, section 5.3.\n"));
1320 * Check the Protocols line and flag PJL + BCP since TBCP is
1321 * usually used with PJL...
1326 if (strstr(ppd
->protocols
, "PJL") &&
1327 strstr(ppd
->protocols
, "BCP") &&
1328 !strstr(ppd
->protocols
, "TBCP"))
1330 _cupsLangPuts(stdout
,
1331 _(" WARN Protocols contains both PJL "
1332 "and BCP; expected TBCP.\n"
1333 " REF: Pages 78-79, section 5.7.\n"));
1336 if (strstr(ppd
->protocols
, "PJL") &&
1337 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1339 _cupsLangPuts(stdout
,
1340 _(" WARN Protocols contains PJL but JCL "
1341 "attributes are not set.\n"
1342 " REF: Pages 78-79, section 5.7.\n"));
1347 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1348 * which are errors according to the spec but won't cause problems
1349 * with CUPS specifically...
1352 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1353 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1355 len
= strlen(option
->keyword
);
1357 for (m
= 0, group2
= ppd
->groups
;
1358 m
< ppd
->num_groups
;
1360 for (n
= 0, option2
= group2
->options
;
1361 n
< group2
->num_options
;
1363 if (option
!= option2
&&
1364 len
< strlen(option2
->keyword
) &&
1365 !strncmp(option
->keyword
, option2
->keyword
, len
))
1367 _cupsLangPrintf(stdout
,
1368 _(" WARN %s shares a common "
1370 " REF: Page 15, section "
1372 option
->keyword
, option2
->keyword
);
1382 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
1384 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
1386 if ((!attr
->value
|| access(attr
->value
, 0)) && verbose
>= 0)
1387 _cupsLangPrintf(stdout
, _(" WARN Missing "
1388 "APDialogExtension file \"%s\"\n"),
1389 attr
->value
? attr
->value
: "<NULL>");
1396 for (attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
);
1398 attr
= ppdFindNextAttr(ppd
, "APPrinterIconPath", NULL
))
1400 if ((!attr
->value
|| access(attr
->value
, 0)) && verbose
>= 0)
1401 _cupsLangPrintf(stdout
, _(" WARN Missing "
1402 "APPrinterIconPath file \"%s\"\n"),
1403 attr
->value
? attr
->value
: "<NULL>");
1405 #endif /* __APPLE__ */
1410 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1412 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1416 * Then list the options, if "-v" was provided...
1421 _cupsLangPrintf(stdout
,
1423 " language_level = %d\n"
1424 " color_device = %s\n"
1425 " variable_sizes = %s\n"
1426 " landscape = %d\n",
1427 ppd
->language_level
,
1428 ppd
->color_device
? "TRUE" : "FALSE",
1429 ppd
->variable_sizes
? "TRUE" : "FALSE",
1432 switch (ppd
->colorspace
)
1435 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1438 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1441 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1444 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1447 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1451 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1452 ppd
->num_emulations
);
1453 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1454 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1455 j
, ppd
->emulations
[j
].name
);
1457 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1458 ppd
->lang_encoding
);
1459 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1461 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1462 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1463 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1464 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1466 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1467 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1468 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1469 ppd
->shortnickname
);
1470 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1471 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1473 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1474 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1476 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1479 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1481 _cupsLangPrintf(stdout
,
1482 " options[%d] = %s (%s) %s %s %.0f "
1484 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1485 sections
[option
->section
], option
->order
,
1486 option
->num_choices
);
1488 if (!strcmp(option
->keyword
, "PageSize") ||
1489 !strcmp(option
->keyword
, "PageRegion"))
1491 for (m
= option
->num_choices
, choice
= option
->choices
;
1495 size
= ppdPageSize(ppd
, choice
->choice
);
1498 _cupsLangPrintf(stdout
,
1500 choice
->choice
, choice
->text
);
1502 _cupsLangPrintf(stdout
,
1503 " %s (%s) = %.2fx%.2fin "
1504 "(%.1f,%.1f,%.1f,%.1f)",
1505 choice
->choice
, choice
->text
,
1506 size
->width
/ 72.0, size
->length
/ 72.0,
1507 size
->left
/ 72.0, size
->bottom
/ 72.0,
1508 size
->right
/ 72.0, size
->top
/ 72.0);
1510 if (!strcmp(option
->defchoice
, choice
->choice
))
1511 _cupsLangPuts(stdout
, " *\n");
1513 _cupsLangPuts(stdout
, "\n");
1518 for (m
= option
->num_choices
, choice
= option
->choices
;
1522 _cupsLangPrintf(stdout
, " %s (%s)",
1523 choice
->choice
, choice
->text
);
1525 if (!strcmp(option
->defchoice
, choice
->choice
))
1526 _cupsLangPuts(stdout
, " *\n");
1528 _cupsLangPuts(stdout
, "\n");
1534 _cupsLangPrintf(stdout
, " num_consts = %d\n",
1536 for (j
= 0; j
< ppd
->num_consts
; j
++)
1537 _cupsLangPrintf(stdout
,
1538 " consts[%d] = *%s %s *%s %s\n",
1539 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1540 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1542 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1544 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1545 _cupsLangPrintf(stdout
,
1546 " profiles[%d] = %s/%s %.3f %.3f "
1547 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1548 j
, ppd
->profiles
[j
].resolution
,
1549 ppd
->profiles
[j
].media_type
,
1550 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1551 ppd
->profiles
[j
].matrix
[0][0],
1552 ppd
->profiles
[j
].matrix
[0][1],
1553 ppd
->profiles
[j
].matrix
[0][2],
1554 ppd
->profiles
[j
].matrix
[1][0],
1555 ppd
->profiles
[j
].matrix
[1][1],
1556 ppd
->profiles
[j
].matrix
[1][2],
1557 ppd
->profiles
[j
].matrix
[2][0],
1558 ppd
->profiles
[j
].matrix
[2][1],
1559 ppd
->profiles
[j
].matrix
[2][2]);
1561 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1562 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1563 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1566 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1567 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1568 _cupsLangPrintf(stdout
,
1569 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1570 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1571 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1572 ppd
->attrs
[j
]->text
,
1573 ppd
->attrs
[j
]->value
?
1574 ppd
->attrs
[j
]->value
: "(null)");
1588 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1592 check_basics(const char *filename
) /* I - PPD file to check */
1594 cups_file_t
*fp
; /* File pointer */
1595 int ch
; /* Current character */
1596 int col
, /* Current column */
1597 whitespace
; /* Only seen whitespace? */
1598 int eol
; /* Line endings */
1599 int linenum
; /* Line number */
1600 int mixed
; /* Mixed line endings? */
1603 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1612 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1614 if (ch
== '\r' || ch
== '\n')
1618 if (eol
== EOL_NONE
)
1620 else if (eol
!= EOL_LF
)
1623 else if (ch
== '\r')
1625 if (cupsFilePeekChar(fp
) == '\n')
1627 cupsFileGetChar(fp
);
1629 if (eol
== EOL_NONE
)
1631 else if (eol
!= EOL_CRLF
)
1634 else if (eol
== EOL_NONE
)
1636 else if (eol
!= EOL_CR
)
1640 if (col
> 0 && whitespace
)
1641 _cupsLangPrintf(stdout
,
1642 _(" WARN Line %d only contains whitespace!\n"),
1651 if (ch
!= ' ' && ch
!= '\t')
1659 _cupsLangPuts(stdout
,
1660 _(" WARN File contains a mix of CR, LF, and "
1661 "CR LF line endings!\n"));
1663 if (eol
== EOL_CRLF
)
1664 _cupsLangPuts(stdout
,
1665 _(" WARN Non-Windows PPD files should use lines "
1666 "ending with only LF, not CR LF!\n"));
1673 * 'check_constraints()' - Check UIConstraints in the PPD file.
1676 static int /* O - Errors found */
1677 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1678 int errors
, /* I - Errors found */
1679 int verbose
, /* I - Verbosity level */
1680 int warn
) /* I - Warnings only? */
1682 int j
; /* Looping var */
1683 ppd_const_t
*c
; /* Current constraint */
1684 ppd_option_t
*option
; /* Standard UI option */
1685 ppd_option_t
*option2
; /* Standard UI option */
1686 const char *prefix
; /* WARN/FAIL prefix */
1689 prefix
= warn
? " WARN " : "**FAIL**";
1691 for (j
= ppd
->num_consts
, c
= ppd
->consts
; j
> 0; j
--, c
++)
1693 option
= ppdFindOption(ppd
, c
->option1
);
1694 option2
= ppdFindOption(ppd
, c
->option2
);
1696 if (!option
|| !option2
)
1698 if (!warn
&& !errors
&& !verbose
)
1699 _cupsLangPuts(stdout
, _(" FAIL\n"));
1702 _cupsLangPrintf(stdout
,
1703 _(" %s Missing option %s in "
1704 "UIConstraint \"*%s %s *%s %s\"!\n"),
1706 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1709 _cupsLangPrintf(stdout
,
1710 _(" %s Missing option %s in "
1711 "UIConstraint \"*%s %s *%s %s\"!\n"),
1713 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1721 if (c
->choice1
[0] && !ppdFindChoice(option
, c
->choice1
))
1723 if (!warn
&& !errors
&& !verbose
)
1724 _cupsLangPuts(stdout
, _(" FAIL\n"));
1726 _cupsLangPrintf(stdout
,
1727 _(" %s Missing choice *%s %s in "
1728 "UIConstraint \"*%s %s *%s %s\"!\n"),
1729 prefix
, c
->option1
, c
->choice1
,
1730 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1736 if (c
->choice2
[0] && !ppdFindChoice(option2
, c
->choice2
))
1738 if (!warn
&& !errors
&& !verbose
)
1739 _cupsLangPuts(stdout
, _(" FAIL\n"));
1741 _cupsLangPrintf(stdout
,
1742 _(" %s Missing choice *%s %s in "
1743 "UIConstraint \"*%s %s *%s %s\"!\n"),
1744 prefix
, c
->option2
, c
->choice2
,
1745 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1757 * 'check_defaults()' - Check default option keywords in the PPD file.
1760 static int /* O - Errors found */
1761 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
1762 int errors
, /* I - Errors found */
1763 int verbose
, /* I - Verbosity level */
1764 int warn
) /* I - Warnings only? */
1766 int j
, k
; /* Looping vars */
1767 ppd_attr_t
*attr
; /* PPD attribute */
1768 ppd_option_t
*option
; /* Standard UI option */
1769 const char *prefix
; /* WARN/FAIL prefix */
1772 prefix
= warn
? " WARN " : "**FAIL**";
1774 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1776 attr
= ppd
->attrs
[j
];
1778 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1779 !strcmp(attr
->name
, "DefaultFont") ||
1780 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1781 !strcmp(attr
->name
, "DefaultImageableArea") ||
1782 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1783 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1784 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1785 !strcmp(attr
->name
, "DefaultResolution") ||
1786 !strcmp(attr
->name
, "DefaultTransfer"))
1789 if (!strncmp(attr
->name
, "Default", 7))
1791 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
1792 strcmp(attr
->value
, "Unknown"))
1795 * Check that the default option value matches a choice...
1798 for (k
= 0; k
< option
->num_choices
; k
++)
1799 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
1802 if (k
>= option
->num_choices
)
1804 if (!warn
&& !errors
&& !verbose
)
1805 _cupsLangPuts(stdout
, _(" FAIL\n"));
1808 _cupsLangPrintf(stdout
,
1809 _(" %s %s %s does not exist!\n"),
1810 prefix
, attr
->name
, attr
->value
);
1824 * 'check_filters()' - Check filters in the PPD file.
1827 static int /* O - Errors found */
1828 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
1829 const char *root
, /* I - Root directory */
1830 int errors
, /* I - Errors found */
1831 int verbose
, /* I - Verbosity level */
1832 int warn
) /* I - Warnings only? */
1834 int i
; /* Looping var */
1835 ppd_attr_t
*attr
; /* PPD attribute */
1836 const char *ptr
; /* Pointer into string */
1837 char super
[16], /* Super-type for filter */
1838 type
[256], /* Type for filter */
1839 program
[1024], /* Program/filter name */
1840 pathprog
[1024]; /* Complete path to program/filter */
1841 int cost
; /* Cost of filter */
1842 const char *prefix
; /* WARN/FAIL prefix */
1845 prefix
= warn
? " WARN " : "**FAIL**";
1847 for (i
= 0; i
< ppd
->num_filters
; i
++)
1849 if (sscanf(ppd
->filters
[i
], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
1850 &cost
, program
) != 4)
1852 if (!warn
&& !errors
&& !verbose
)
1853 _cupsLangPuts(stdout
, _(" FAIL\n"));
1856 _cupsLangPrintf(stdout
,
1857 _(" %s Bad cupsFilter value \"%s\"!\n"),
1858 prefix
, ppd
->filters
[i
]);
1865 if (program
[0] == '/')
1866 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1869 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1870 ptr
= CUPS_SERVERBIN
;
1872 if (*ptr
== '/' || !*root
)
1873 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1876 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1880 if (access(pathprog
, X_OK
))
1882 if (!warn
&& !errors
&& !verbose
)
1883 _cupsLangPuts(stdout
, _(" FAIL\n"));
1886 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
1887 "file \"%s\"\n"), prefix
, program
);
1895 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
1897 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
1900 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
1901 &cost
, program
) != 4)
1903 if (!warn
&& !errors
&& !verbose
)
1904 _cupsLangPuts(stdout
, _(" FAIL\n"));
1907 _cupsLangPrintf(stdout
,
1908 _(" %s Bad cupsPreFilter value \"%s\"!\n"),
1909 prefix
, attr
->value
? attr
->value
: "");
1916 if (program
[0] == '/')
1917 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1920 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1921 ptr
= CUPS_SERVERBIN
;
1923 if (*ptr
== '/' || !*root
)
1924 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1927 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1931 if (access(pathprog
, X_OK
))
1933 if (!warn
&& !errors
&& !verbose
)
1934 _cupsLangPuts(stdout
, _(" FAIL\n"));
1937 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
1938 "file \"%s\"\n"), prefix
, program
);
1951 * 'check_profiles()' - Check ICC color profiles in the PPD file.
1954 static int /* O - Errors found */
1955 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
1956 const char *root
, /* I - Root directory */
1957 int errors
, /* I - Errors found */
1958 int verbose
, /* I - Verbosity level */
1959 int warn
) /* I - Warnings only? */
1961 int i
; /* Looping var */
1962 ppd_attr_t
*attr
; /* PPD attribute */
1963 const char *ptr
; /* Pointer into string */
1964 const char *prefix
; /* WARN/FAIL prefix */
1965 char filename
[1024]; /* Profile filename */
1966 int num_profiles
= 0; /* Number of profiles */
1967 unsigned hash
, /* Current hash value */
1968 hashes
[1000]; /* Hash values of profile names */
1969 const char *specs
[1000]; /* Specifiers for profiles */
1972 prefix
= warn
? " WARN " : "**FAIL**";
1974 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
1976 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
1979 * Check for valid selector...
1982 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
1985 if (!attr
->value
|| i
< 2)
1987 if (!warn
&& !errors
&& !verbose
)
1988 _cupsLangPuts(stdout
, _(" FAIL\n"));
1991 _cupsLangPrintf(stdout
,
1992 _(" %s Bad cupsICCProfile %s!\n"),
1993 prefix
, attr
->spec
);
2002 * Check for valid profile filename...
2005 if (attr
->value
[0] == '/')
2006 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
2009 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
2012 if (*ptr
== '/' || !*root
)
2013 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
2016 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
2020 if (access(filename
, 0))
2022 if (!warn
&& !errors
&& !verbose
)
2023 _cupsLangPuts(stdout
, _(" FAIL\n"));
2026 _cupsLangPrintf(stdout
, _(" %s Missing cupsICCProfile "
2027 "file \"%s\"!\n"), prefix
, attr
->value
);
2034 * Check for hash collisions...
2037 hash
= _ppdHashName(attr
->spec
);
2039 if (num_profiles
> 0)
2041 for (i
= 0; i
< num_profiles
; i
++)
2042 if (hashes
[i
] == hash
)
2045 if (i
< num_profiles
)
2047 if (!warn
&& !errors
&& !verbose
)
2048 _cupsLangPuts(stdout
, _(" FAIL\n"));
2051 _cupsLangPrintf(stdout
,
2052 _(" %s cupsICCProfile %s hash value "
2053 "collides with %s!\n"), prefix
, attr
->spec
,
2062 * Remember up to 1000 profiles...
2065 if (num_profiles
< 1000)
2067 hashes
[num_profiles
] = hash
;
2068 specs
[num_profiles
] = attr
->spec
;
2078 * 'check_translations()' - Check translations in the PPD file.
2081 static int /* O - Errors found */
2082 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
2083 int errors
, /* I - Errors found */
2084 int verbose
, /* I - Verbosity level */
2085 int warn
) /* I - Warnings only? */
2087 int j
; /* Looping var */
2088 ppd_attr_t
*attr
; /* PPD attribute */
2089 cups_array_t
*languages
; /* Array of languages */
2090 int langlen
; /* Length of language */
2091 char *language
, /* Current language */
2092 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
2093 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
2094 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
2095 cllkeyword
[PPD_MAX_NAME
];
2096 /* Custom option keyword (base) */
2097 ppd_option_t
*option
; /* Standard UI option */
2098 ppd_coption_t
*coption
; /* Custom option */
2099 ppd_cparam_t
*cparam
; /* Custom parameter */
2100 char ll
[3]; /* Base language */
2101 const char *prefix
; /* WARN/FAIL prefix */
2104 prefix
= warn
? " WARN " : "**FAIL**";
2106 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
2109 * This file contains localizations, check them...
2112 for (language
= (char *)cupsArrayFirst(languages
);
2114 language
= (char *)cupsArrayNext(languages
))
2116 langlen
= strlen(language
);
2117 if (langlen
!= 2 && langlen
!= 5)
2119 if (!warn
&& !errors
&& !verbose
)
2120 _cupsLangPuts(stdout
, _(" FAIL\n"));
2123 _cupsLangPrintf(stdout
,
2124 _(" %s Bad language \"%s\"!\n"),
2133 if (!strcmp(language
, "en"))
2136 strlcpy(ll
, language
, sizeof(ll
));
2139 * Loop through all options and choices...
2142 for (option
= ppdFirstOption(ppd
);
2144 option
= ppdNextOption(ppd
))
2146 if (!strcmp(option
->keyword
, "PageRegion"))
2149 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
2150 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
2152 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
2153 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
2155 if (!warn
&& !errors
&& !verbose
)
2156 _cupsLangPuts(stdout
, _(" FAIL\n"));
2159 _cupsLangPrintf(stdout
,
2160 _(" %s Missing \"%s\" translation "
2161 "string for option %s!\n"),
2162 prefix
, language
, option
->keyword
);
2167 else if (!valid_utf8(attr
->text
))
2169 if (!warn
&& !errors
&& !verbose
)
2170 _cupsLangPuts(stdout
, _(" FAIL\n"));
2173 _cupsLangPrintf(stdout
,
2174 _(" %s Bad UTF-8 \"%s\" translation "
2175 "string for option %s!\n"),
2176 prefix
, language
, option
->keyword
);
2182 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
2184 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
2187 for (j
= 0; j
< option
->num_choices
; j
++)
2189 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
2190 (coption
= ppdFindCustomOption(ppd
,
2191 option
->keyword
)) != NULL
)
2193 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
2194 language
, option
->keyword
);
2196 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
2197 !valid_utf8(attr
->text
))
2199 if (!warn
&& !errors
&& !verbose
)
2200 _cupsLangPuts(stdout
, _(" FAIL\n"));
2203 _cupsLangPrintf(stdout
,
2204 _(" %s Bad UTF-8 \"%s\" "
2205 "translation string for option %s, "
2208 ckeyword
+ 1 + strlen(language
),
2215 if (strcasecmp(option
->keyword
, "PageSize"))
2217 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
2219 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
2221 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
2222 language
, option
->keyword
);
2223 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
2224 ll
, option
->keyword
);
2226 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
2227 cparam
->name
)) == NULL
&&
2228 (attr
= ppdFindAttr(ppd
, cllkeyword
,
2229 cparam
->name
)) == NULL
)
2231 if (!warn
&& !errors
&& !verbose
)
2232 _cupsLangPuts(stdout
, _(" FAIL\n"));
2235 _cupsLangPrintf(stdout
,
2236 _(" %s Missing \"%s\" "
2237 "translation string for option %s, "
2240 ckeyword
+ 1 + strlen(language
),
2246 else if (!valid_utf8(attr
->text
))
2248 if (!warn
&& !errors
&& !verbose
)
2249 _cupsLangPuts(stdout
, _(" FAIL\n"));
2252 _cupsLangPrintf(stdout
,
2253 _(" %s Bad UTF-8 \"%s\" "
2254 "translation string for option %s, "
2257 ckeyword
+ 1 + strlen(language
),
2266 else if ((attr
= ppdFindAttr(ppd
, keyword
,
2267 option
->choices
[j
].choice
)) == NULL
&&
2268 (attr
= ppdFindAttr(ppd
, llkeyword
,
2269 option
->choices
[j
].choice
)) == NULL
)
2271 if (!warn
&& !errors
&& !verbose
)
2272 _cupsLangPuts(stdout
, _(" FAIL\n"));
2275 _cupsLangPrintf(stdout
,
2276 _(" %s Missing \"%s\" "
2277 "translation string for option %s, "
2279 prefix
, language
, option
->keyword
,
2280 option
->choices
[j
].choice
);
2285 else if (!valid_utf8(attr
->text
))
2287 if (!warn
&& !errors
&& !verbose
)
2288 _cupsLangPuts(stdout
, _(" FAIL\n"));
2291 _cupsLangPrintf(stdout
,
2292 _(" %s Bad UTF-8 \"%s\" "
2293 "translation string for option %s, "
2295 prefix
, language
, option
->keyword
,
2296 option
->choices
[j
].choice
);
2306 * Verify that we have the base language for each localized one...
2309 for (language
= (char *)cupsArrayFirst(languages
);
2311 language
= (char *)cupsArrayNext(languages
))
2315 * Lookup the base language...
2318 cupsArraySave(languages
);
2320 strlcpy(ll
, language
, sizeof(ll
));
2322 if (!cupsArrayFind(languages
, ll
) && strcmp(ll
, "zh"))
2324 if (!warn
&& !errors
&& !verbose
)
2325 _cupsLangPuts(stdout
, _(" FAIL\n"));
2328 _cupsLangPrintf(stdout
,
2329 _(" %s No base translation \"%s\" "
2330 "is included in file!\n"), prefix
, ll
);
2336 cupsArrayRestore(languages
);
2340 * Free memory used for the languages...
2343 _ppdFreeLanguages(languages
);
2351 * 'show_conflicts()' - Show option conflicts in a PPD file.
2355 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
2357 int i
, j
; /* Looping variables */
2358 ppd_const_t
*c
; /* Current constraint */
2359 ppd_option_t
*o1
, *o2
; /* Options */
2360 ppd_choice_t
*c1
, *c2
; /* Choices */
2364 * Loop through all of the UI constraints and report any options
2368 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
2371 * Grab pointers to the first option...
2374 o1
= ppdFindOption(ppd
, c
->option1
);
2378 else if (c
->choice1
[0] != '\0')
2381 * This constraint maps to a specific choice.
2384 c1
= ppdFindChoice(o1
, c
->choice1
);
2389 * This constraint applies to any choice for this option.
2392 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
2397 !strcasecmp(c1
->choice
, "None") ||
2398 !strcasecmp(c1
->choice
, "Off") ||
2399 !strcasecmp(c1
->choice
, "False"))
2404 * Grab pointers to the second option...
2407 o2
= ppdFindOption(ppd
, c
->option2
);
2411 else if (c
->choice2
[0] != '\0')
2414 * This constraint maps to a specific choice.
2417 c2
= ppdFindChoice(o2
, c
->choice2
);
2422 * This constraint applies to any choice for this option.
2425 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
2430 !strcasecmp(c2
->choice
, "None") ||
2431 !strcasecmp(c2
->choice
, "Off") ||
2432 !strcasecmp(c2
->choice
, "False"))
2437 * If both options are marked then there is a conflict...
2440 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
2441 _cupsLangPrintf(stdout
,
2442 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
2443 " (constraint=\"%s %s %s %s\")\n"),
2444 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
2445 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2451 * 'test_raster()' - Test PostScript commands for raster printers.
2454 static int /* O - 1 on success, 0 on failure */
2455 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
2456 int verbose
) /* I - Verbosity */
2458 cups_page_header2_t header
; /* Page header */
2461 ppdMarkDefaults(ppd
);
2462 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
2465 _cupsLangPuts(stdout
, _(" FAIL\n"));
2468 _cupsLangPrintf(stdout
,
2469 _(" **FAIL** Default option code cannot be "
2470 "interpreted: %s\n"), cupsRasterErrorString());
2476 * Try a test of custom page size code, if available...
2479 if (!ppdPageSize(ppd
, "Custom.612x792"))
2482 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
2484 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
2487 _cupsLangPuts(stdout
, _(" FAIL\n"));
2490 _cupsLangPrintf(stdout
,
2491 _(" **FAIL** Default option code cannot be "
2492 "interpreted: %s\n"), cupsRasterErrorString());
2502 * 'usage()' - Show program usage...
2508 _cupsLangPuts(stdout
,
2509 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
2510 "[... filenameN.ppd[.gz]]\n"
2511 " program | cupstestppd [options] -\n"
2515 " -R root-directory Set alternate root\n"
2516 " -W {all,none,constraints,defaults,filters,translations}\n"
2517 " Issue warnings instead of errors\n"
2518 " -q Run silently\n"
2519 " -r Use 'relaxed' open mode\n"
2520 " -v Be slightly verbose\n"
2521 " -vv Be very verbose\n"));
2528 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
2531 static int /* O - 1 if valid, 0 if not */
2532 valid_utf8(const char *s
) /* I - String to check */
2539 * Check for valid UTF-8 sequence...
2542 if ((*s
& 0xc0) == 0x80)
2543 return (0); /* Illegal suffix byte */
2544 else if ((*s
& 0xe0) == 0xc0)
2547 * 2-byte sequence...
2552 if ((*s
& 0xc0) != 0x80)
2553 return (0); /* Missing suffix byte */
2555 else if ((*s
& 0xf0) == 0xe0)
2558 * 3-byte sequence...
2563 if ((*s
& 0xc0) != 0x80)
2564 return (0); /* Missing suffix byte */
2568 if ((*s
& 0xc0) != 0x80)
2569 return (0); /* Missing suffix byte */
2571 else if ((*s
& 0xf8) == 0xf0)
2574 * 4-byte sequence...
2579 if ((*s
& 0xc0) != 0x80)
2580 return (0); /* Missing suffix byte */
2584 if ((*s
& 0xc0) != 0x80)
2585 return (0); /* Missing suffix byte */
2589 if ((*s
& 0xc0) != 0x80)
2590 return (0); /* Missing suffix byte */
2593 return (0); /* Bad sequence */
2604 * End of "$Id: cupstestppd.c 7637 2008-06-11 17:25:36Z mike $".