2 * "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $"
4 * PPD test program for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2010 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_case() - Check that there are no duplicate groups, options,
26 * or choices that differ only by case.
27 * check_defaults() - Check default option keywords in the PPD file.
28 * check_duplex() - Check duplex keywords in the PPD file.
29 * check_filters() - Check filters in the PPD file.
30 * check_profiles() - Check ICC color profiles in the PPD file.
31 * check_sizes() - Check media sizes in the PPD file.
32 * check_translations() - Check translations in the PPD file.
33 * show_conflicts() - Show option conflicts in a PPD file.
34 * test_raster() - Test PostScript commands for raster printers.
35 * usage() - Show program usage...
36 * valid_path() - Check whether a path has the correct capitalization.
37 * valid_utf8() - Check whether a string contains valid UTF-8 text.
41 * Include necessary headers...
44 #include <cups/string.h>
45 #include <cups/cups.h>
47 #include <cups/ppd-private.h>
48 #include <cups/i18n.h>
49 #include <cups/raster.h>
59 * Error warning overrides...
69 WARN_TRANSLATIONS
= 16,
105 * File permissions...
108 #define MODE_WRITE 0022 /* Group/other write */
109 #define MODE_MASK 0555 /* Owner/group/other read+exec/search */
110 #define MODE_DATAFILE 0444 /* Owner/group/other read */
111 #define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
112 #define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
119 static void check_basics(const char *filename
);
120 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
122 static int check_case(ppd_file_t
*ppd
, int errors
, int verbose
);
123 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
125 static int check_duplex(ppd_file_t
*ppd
, int errors
, int verbose
,
127 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
128 int verbose
, int warn
);
129 static int check_profiles(ppd_file_t
*ppd
, const char *root
, int errors
,
130 int verbose
, int warn
);
131 static int check_sizes(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
132 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,
134 static void show_conflicts(ppd_file_t
*ppd
);
135 static int test_raster(ppd_file_t
*ppd
, int verbose
);
136 static void usage(void);
137 static int valid_path(const char *keyword
, const char *path
, int errors
,
138 int verbose
, int warn
);
139 static int valid_utf8(const char *s
);
143 * 'main()' - Main entry for test program.
146 int /* O - Exit status */
147 main(int argc
, /* I - Number of command-line args */
148 char *argv
[]) /* I - Command-line arguments */
150 int i
, j
, k
, m
, n
; /* Looping vars */
151 int len
; /* Length of option name */
152 char *opt
; /* Option character */
153 const char *ptr
; /* Pointer into string */
154 int files
; /* Number of files */
155 int verbose
; /* Want verbose output? */
156 int warn
; /* Which errors to just warn about */
157 int ignore
; /* Which errors to ignore */
158 int status
; /* Exit status */
159 int errors
; /* Number of conformance errors */
160 int ppdversion
; /* PPD spec version in PPD file */
161 ppd_status_t error
; /* Status of ppdOpen*() */
162 int line
; /* Line number for error */
163 char *root
; /* Root directory */
164 int xdpi
, /* X resolution */
165 ydpi
; /* Y resolution */
166 ppd_file_t
*ppd
; /* PPD file record */
167 ppd_attr_t
*attr
; /* PPD attribute */
168 ppd_size_t
*size
; /* Size record */
169 ppd_group_t
*group
; /* UI group */
170 ppd_option_t
*option
; /* Standard UI option */
171 ppd_group_t
*group2
; /* UI group */
172 ppd_option_t
*option2
; /* Standard UI option */
173 ppd_choice_t
*choice
; /* Standard UI option choice */
174 struct lconv
*loc
; /* Locale data */
175 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
176 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
177 "JCL", "PAGE", "PROLOG" };
180 _cupsSetLocale(argv
);
184 * Display PPD files for each file listed on the command-line...
187 ppdSetConformance(PPD_CONFORM_STRICT
);
197 for (i
= 1; i
< argc
; i
++)
198 if (argv
[i
][0] == '-' && argv
[i
][1])
200 for (opt
= argv
[i
] + 1; *opt
; opt
++)
203 case 'I' : /* Ignore errors */
209 if (!strcmp(argv
[i
], "none"))
211 else if (!strcmp(argv
[i
], "filename"))
212 ignore
|= WARN_FILENAME
;
213 else if (!strcmp(argv
[i
], "filters"))
214 ignore
|= WARN_FILTERS
;
215 else if (!strcmp(argv
[i
], "profiles"))
216 ignore
|= WARN_PROFILES
;
217 else if (!strcmp(argv
[i
], "all"))
218 ignore
= WARN_FILTERS
| WARN_PROFILES
;
223 case 'R' : /* Alternate root directory */
232 case 'W' : /* Turn errors into warnings */
238 if (!strcmp(argv
[i
], "none"))
240 else if (!strcmp(argv
[i
], "constraints"))
241 warn
|= WARN_CONSTRAINTS
;
242 else if (!strcmp(argv
[i
], "defaults"))
243 warn
|= WARN_DEFAULTS
;
244 else if (!strcmp(argv
[i
], "duplex"))
246 else if (!strcmp(argv
[i
], "filters"))
247 warn
|= WARN_FILTERS
;
248 else if (!strcmp(argv
[i
], "profiles"))
249 warn
|= WARN_PROFILES
;
250 else if (!strcmp(argv
[i
], "sizes"))
252 else if (!strcmp(argv
[i
], "translations"))
253 warn
|= WARN_TRANSLATIONS
;
254 else if (!strcmp(argv
[i
], "all"))
260 case 'q' : /* Quiet mode */
263 _cupsLangPuts(stderr
,
264 _("cupstestppd: The -q option is incompatible "
265 "with the -v option.\n"));
272 case 'r' : /* Relaxed mode */
273 ppdSetConformance(PPD_CONFORM_RELAXED
);
276 case 'v' : /* Verbose mode */
279 _cupsLangPuts(stderr
,
280 _("cupstestppd: The -v option is incompatible "
281 "with the -q option.\n"));
296 * Open the PPD file...
299 if (files
&& verbose
>= 0)
300 _cupsLangPuts(stdout
, "\n");
304 if (argv
[i
][0] == '-')
310 ppd
= ppdOpen(stdin
);
313 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
318 * Read from a file...
322 printf("%s:", argv
[i
]);
324 ppd
= ppdOpenFile(argv
[i
]);
329 error
= ppdLastError(&line
);
331 if (error
<= PPD_ALLOC_ERROR
)
333 status
= ERROR_FILE_OPEN
;
336 _cupsLangPrintf(stdout
,
338 " **FAIL** Unable to open PPD file - %s\n"),
343 status
= ERROR_PPD_FORMAT
;
347 _cupsLangPrintf(stdout
,
349 " **FAIL** Unable to open PPD file - "
351 ppdErrorString(error
), line
);
355 case PPD_MISSING_PPDADOBE4
:
356 _cupsLangPuts(stdout
,
357 _(" REF: Page 42, section 5.2.\n"));
359 case PPD_MISSING_VALUE
:
360 _cupsLangPuts(stdout
,
361 _(" REF: Page 20, section 3.4.\n"));
363 case PPD_BAD_OPEN_GROUP
:
364 case PPD_NESTED_OPEN_GROUP
:
365 _cupsLangPuts(stdout
,
366 _(" REF: Pages 45-46, section 5.2.\n"));
368 case PPD_BAD_OPEN_UI
:
369 case PPD_NESTED_OPEN_UI
:
370 _cupsLangPuts(stdout
,
371 _(" REF: Pages 42-45, section 5.2.\n"));
373 case PPD_BAD_ORDER_DEPENDENCY
:
374 _cupsLangPuts(stdout
,
375 _(" REF: Pages 48-49, section 5.2.\n"));
377 case PPD_BAD_UI_CONSTRAINTS
:
378 _cupsLangPuts(stdout
,
379 _(" REF: Pages 52-54, section 5.2.\n"));
381 case PPD_MISSING_ASTERISK
:
382 _cupsLangPuts(stdout
,
383 _(" REF: Page 15, section 3.2.\n"));
385 case PPD_LINE_TOO_LONG
:
386 _cupsLangPuts(stdout
,
387 _(" REF: Page 15, section 3.1.\n"));
389 case PPD_ILLEGAL_CHARACTER
:
390 _cupsLangPuts(stdout
,
391 _(" REF: Page 15, section 3.1.\n"));
393 case PPD_ILLEGAL_MAIN_KEYWORD
:
394 _cupsLangPuts(stdout
,
395 _(" REF: Pages 16-17, section 3.2.\n"));
397 case PPD_ILLEGAL_OPTION_KEYWORD
:
398 _cupsLangPuts(stdout
,
399 _(" REF: Page 19, section 3.3.\n"));
401 case PPD_ILLEGAL_TRANSLATION
:
402 _cupsLangPuts(stdout
,
403 _(" REF: Page 27, section 3.5.\n"));
409 check_basics(argv
[i
]);
417 * Show the header and then perform basic conformance tests (limited
418 * only by what the CUPS PPD functions actually load...)
425 _cupsLangPuts(stdout
,
426 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
428 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
430 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
432 for (j
= 0; j
< ppd
->num_filters
; j
++)
433 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
435 if (!test_raster(ppd
, verbose
))
441 * Look for default keywords with no matching option...
444 if (!(warn
& WARN_DEFAULTS
))
445 errors
= check_defaults(ppd
, errors
, verbose
, 0);
447 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
451 if (!errors
&& !verbose
)
452 _cupsLangPuts(stdout
, _(" FAIL\n"));
454 _cupsLangPuts(stdout
,
455 _(" **FAIL** REQUIRED DefaultImageableArea\n"
456 " REF: Page 102, section 5.15.\n"));
461 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
462 strcmp(attr
->value
, "Unknown"))
466 if (!errors
&& !verbose
)
467 _cupsLangPuts(stdout
, _(" FAIL\n"));
469 _cupsLangPrintf(stdout
,
470 _(" **FAIL** BAD DefaultImageableArea %s\n"
471 " REF: Page 102, section 5.15.\n"),
480 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
483 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
487 if (!errors
&& !verbose
)
488 _cupsLangPuts(stdout
, _(" FAIL\n"));
490 _cupsLangPuts(stdout
,
491 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
492 " REF: Page 103, section 5.15.\n"));
497 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
498 strcmp(attr
->value
, "Unknown"))
502 if (!errors
&& !verbose
)
503 _cupsLangPuts(stdout
, _(" FAIL\n"));
505 _cupsLangPrintf(stdout
,
506 _(" **FAIL** BAD DefaultPaperDimension %s\n"
507 " REF: Page 103, section 5.15.\n"),
513 else if (verbose
> 0)
514 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
516 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
517 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
520 * Verify that we have a default choice...
523 if (option
->defchoice
[0])
525 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
526 strcmp(option
->defchoice
, "Unknown"))
530 if (!errors
&& !verbose
)
531 _cupsLangPuts(stdout
, _(" FAIL\n"));
533 _cupsLangPrintf(stdout
,
534 _(" **FAIL** BAD Default%s %s\n"
535 " REF: Page 40, section 4.5.\n"),
536 option
->keyword
, option
->defchoice
);
541 else if (verbose
> 0)
542 _cupsLangPrintf(stdout
,
543 _(" PASS Default%s\n"),
550 if (!errors
&& !verbose
)
551 _cupsLangPuts(stdout
, _(" FAIL\n"));
553 _cupsLangPrintf(stdout
,
554 _(" **FAIL** REQUIRED Default%s\n"
555 " REF: Page 40, section 4.5.\n"),
563 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
565 for (ptr
= attr
->value
; *ptr
; ptr
++)
566 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
573 if (!errors
&& !verbose
)
574 _cupsLangPuts(stdout
, _(" FAIL\n"));
576 _cupsLangPrintf(stdout
,
577 _(" **FAIL** Bad FileVersion \"%s\"\n"
578 " REF: Page 56, section 5.3.\n"),
584 else if (verbose
> 0)
585 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
591 if (!errors
&& !verbose
)
592 _cupsLangPuts(stdout
, _(" FAIL\n"));
594 _cupsLangPuts(stdout
,
595 _(" **FAIL** REQUIRED FileVersion\n"
596 " REF: Page 56, section 5.3.\n"));
602 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
605 if (*ptr
== '4' && ptr
[1] == '.')
608 for (ptr
+= 2; *ptr
; ptr
++)
609 if (!isdigit(*ptr
& 255))
617 if (!errors
&& !verbose
)
618 _cupsLangPuts(stdout
, _(" FAIL\n"));
620 _cupsLangPrintf(stdout
,
621 _(" **FAIL** Bad FormatVersion \"%s\"\n"
622 " REF: Page 56, section 5.3.\n"),
628 else if (verbose
> 0)
629 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
635 if (!errors
&& !verbose
)
636 _cupsLangPuts(stdout
, _(" FAIL\n"));
638 _cupsLangPuts(stdout
,
639 _(" **FAIL** REQUIRED FormatVersion\n"
640 " REF: Page 56, section 5.3.\n"));
646 if (ppd
->lang_encoding
!= NULL
)
649 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
651 else if (ppdversion
> 40)
655 if (!errors
&& !verbose
)
656 _cupsLangPuts(stdout
, _(" FAIL\n"));
658 _cupsLangPuts(stdout
,
659 _(" **FAIL** REQUIRED LanguageEncoding\n"
660 " REF: Pages 56-57, section 5.3.\n"));
666 if (ppd
->lang_version
!= NULL
)
669 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
675 if (!errors
&& !verbose
)
676 _cupsLangPuts(stdout
, _(" FAIL\n"));
678 _cupsLangPuts(stdout
,
679 _(" **FAIL** REQUIRED LanguageVersion\n"
680 " REF: Pages 57-58, section 5.3.\n"));
686 if (ppd
->manufacturer
!= NULL
)
688 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
689 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
693 if (!errors
&& !verbose
)
694 _cupsLangPuts(stdout
, _(" FAIL\n"));
696 _cupsLangPuts(stdout
,
697 _(" **FAIL** BAD Manufacturer (should be "
699 " REF: Page 211, table D.1.\n"));
704 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
705 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
709 if (!errors
&& !verbose
)
710 _cupsLangPuts(stdout
, _(" FAIL\n"));
712 _cupsLangPuts(stdout
,
713 _(" **FAIL** BAD Manufacturer (should be "
715 " REF: Page 211, table D.1.\n"));
720 else if (verbose
> 0)
721 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
723 else if (ppdversion
>= 43)
727 if (!errors
&& !verbose
)
728 _cupsLangPuts(stdout
, _(" FAIL\n"));
730 _cupsLangPuts(stdout
,
731 _(" **FAIL** REQUIRED Manufacturer\n"
732 " REF: Pages 58-59, section 5.3.\n"));
738 if (ppd
->modelname
!= NULL
)
740 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
741 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
748 if (!errors
&& !verbose
)
749 _cupsLangPuts(stdout
, _(" FAIL\n"));
751 _cupsLangPrintf(stdout
,
752 _(" **FAIL** BAD ModelName - \"%c\" not "
753 "allowed in string.\n"
754 " REF: Pages 59-60, section 5.3.\n"),
760 else if (verbose
> 0)
761 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
767 if (!errors
&& !verbose
)
768 _cupsLangPuts(stdout
, _(" FAIL\n"));
770 _cupsLangPuts(stdout
,
771 _(" **FAIL** REQUIRED ModelName\n"
772 " REF: Pages 59-60, section 5.3.\n"));
778 if (ppd
->nickname
!= NULL
)
781 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
787 if (!errors
&& !verbose
)
788 _cupsLangPuts(stdout
, _(" FAIL\n"));
790 _cupsLangPuts(stdout
,
791 _(" **FAIL** REQUIRED NickName\n"
792 " REF: Page 60, section 5.3.\n"));
798 if (ppdFindOption(ppd
, "PageSize") != NULL
)
801 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
807 if (!errors
&& !verbose
)
808 _cupsLangPuts(stdout
, _(" FAIL\n"));
810 _cupsLangPuts(stdout
,
811 _(" **FAIL** REQUIRED PageSize\n"
812 " REF: Pages 99-100, section 5.14.\n"));
818 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
821 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
827 if (!errors
&& !verbose
)
828 _cupsLangPuts(stdout
, _(" FAIL\n"));
830 _cupsLangPuts(stdout
,
831 _(" **FAIL** REQUIRED PageRegion\n"
832 " REF: Page 100, section 5.14.\n"));
838 if (ppd
->pcfilename
!= NULL
)
841 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
843 else if (!(ignore
& WARN_FILENAME
))
847 if (!errors
&& !verbose
)
848 _cupsLangPuts(stdout
, _(" FAIL\n"));
850 _cupsLangPuts(stdout
,
851 _(" **FAIL** REQUIRED PCFileName\n"
852 " REF: Pages 61-62, section 5.3.\n"));
858 if (ppd
->product
!= NULL
)
860 if (ppd
->product
[0] != '(' ||
861 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
865 if (!errors
&& !verbose
)
866 _cupsLangPuts(stdout
, _(" FAIL\n"));
868 _cupsLangPuts(stdout
,
869 _(" **FAIL** BAD Product - not \"(string)\".\n"
870 " REF: Page 62, section 5.3.\n"));
875 else if (verbose
> 0)
876 _cupsLangPuts(stdout
, _(" PASS Product\n"));
882 if (!errors
&& !verbose
)
883 _cupsLangPuts(stdout
, _(" FAIL\n"));
885 _cupsLangPuts(stdout
,
886 _(" **FAIL** REQUIRED Product\n"
887 " REF: Page 62, section 5.3.\n"));
893 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
896 char junkstr
[255]; /* Temp string */
897 int junkint
; /* Temp integer */
900 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
904 if (!errors
&& !verbose
)
905 _cupsLangPuts(stdout
, _(" FAIL\n"));
907 _cupsLangPuts(stdout
,
908 _(" **FAIL** BAD PSVersion - not \"(string) "
910 " REF: Pages 62-64, section 5.3.\n"));
915 else if (verbose
> 0)
916 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
922 if (!errors
&& !verbose
)
923 _cupsLangPuts(stdout
, _(" FAIL\n"));
925 _cupsLangPuts(stdout
,
926 _(" **FAIL** REQUIRED PSVersion\n"
927 " REF: Pages 62-64, section 5.3.\n"));
933 if (ppd
->shortnickname
!= NULL
)
935 if (strlen(ppd
->shortnickname
) > 31)
939 if (!errors
&& !verbose
)
940 _cupsLangPuts(stdout
, _(" FAIL\n"));
942 _cupsLangPuts(stdout
,
943 _(" **FAIL** BAD ShortNickName - longer "
945 " REF: Pages 64-65, section 5.3.\n"));
950 else if (verbose
> 0)
951 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
953 else if (ppdversion
>= 43)
957 if (!errors
&& !verbose
)
958 _cupsLangPuts(stdout
, _(" FAIL\n"));
960 _cupsLangPuts(stdout
,
961 _(" **FAIL** REQUIRED ShortNickName\n"
962 " REF: Page 64-65, section 5.3.\n"));
968 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
969 strstr(ppd
->patches
, "*End"))
973 if (!errors
&& !verbose
)
974 _cupsLangPuts(stdout
, _(" FAIL\n"));
976 _cupsLangPuts(stdout
,
977 _(" **FAIL** BAD JobPatchFile attribute in file\n"
978 " REF: Page 24, section 3.4.\n"));
985 * Check for page sizes without the corresponding ImageableArea or
986 * PaperDimension values...
989 if (ppd
->num_sizes
== 0)
993 if (!errors
&& !verbose
)
994 _cupsLangPuts(stdout
, _(" FAIL\n"));
996 _cupsLangPuts(stdout
,
997 _(" **FAIL** REQUIRED PageSize\n"
998 " REF: Page 41, section 5.\n"
999 " REF: Page 99, section 5.14.\n"));
1006 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1009 * Don't check custom size...
1012 if (!strcmp(size
->name
, "Custom"))
1016 * Check for ImageableArea...
1019 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1020 size
->right
== 0.0 && size
->top
== 0.0)
1024 if (!errors
&& !verbose
)
1025 _cupsLangPuts(stdout
, _(" FAIL\n"));
1027 _cupsLangPrintf(stdout
,
1028 _(" **FAIL** REQUIRED ImageableArea for "
1030 " REF: Page 41, section 5.\n"
1031 " REF: Page 102, section 5.15.\n"),
1039 * Check for PaperDimension...
1042 if (size
->width
== 0.0 && size
->length
== 0.0)
1046 if (!errors
&& !verbose
)
1047 _cupsLangPuts(stdout
, _(" FAIL\n"));
1049 _cupsLangPrintf(stdout
,
1050 _(" **FAIL** REQUIRED PaperDimension "
1052 " REF: Page 41, section 5.\n"
1053 " REF: Page 103, section 5.15.\n"),
1063 * Check for valid Resolution, JCLResolution, or SetResolution values...
1066 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1067 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1068 option
= ppdFindOption(ppd
, "SetResolution");
1072 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
1075 * Verify that all resolution options are of the form NNNdpi
1079 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1080 if (ptr
> choice
->choice
&& xdpi
> 0)
1083 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1090 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1095 if (!errors
&& !verbose
)
1096 _cupsLangPuts(stdout
, _(" FAIL\n"));
1098 _cupsLangPrintf(stdout
,
1099 _(" **FAIL** Bad %s choice %s\n"
1100 " REF: Page 84, section 5.9\n"),
1101 option
->keyword
, choice
->choice
);
1109 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1110 strcmp(attr
->name
, "1284DeviceID"))
1114 if (!errors
&& !verbose
)
1115 _cupsLangPuts(stdout
, _(" FAIL\n"));
1117 _cupsLangPrintf(stdout
,
1118 _(" **FAIL** %s must be 1284DeviceID\n"
1119 " REF: Page 72, section 5.5\n"),
1126 errors
= check_case(ppd
, errors
, verbose
);
1128 if (!(warn
& WARN_CONSTRAINTS
))
1129 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1131 if (!(warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1132 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1134 if (!(warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1135 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1137 if (!(warn
& WARN_SIZES
))
1138 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1140 if (!(warn
& WARN_TRANSLATIONS
))
1141 errors
= check_translations(ppd
, errors
, verbose
, 0);
1143 if (!(warn
& WARN_DUPLEX
))
1144 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1146 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1150 * This file contains localizations, check for conformance of the
1151 * base translation...
1154 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1156 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1158 if (!errors
&& !verbose
)
1159 _cupsLangPuts(stdout
, _(" FAIL\n"));
1162 _cupsLangPrintf(stdout
,
1163 _(" **FAIL** Bad LanguageEncoding %s - "
1164 "must be ISOLatin1\n"),
1165 attr
->value
? attr
->value
: "(null)");
1170 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1172 if (!errors
&& !verbose
)
1173 _cupsLangPuts(stdout
, _(" FAIL\n"));
1176 _cupsLangPrintf(stdout
,
1177 _(" **FAIL** Bad LanguageVersion %s - "
1178 "must be English\n"),
1179 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1185 * Loop through all options and choices...
1188 for (option
= ppdFirstOption(ppd
);
1190 option
= ppdNextOption(ppd
))
1193 * Check for special characters outside A0 to BF, F7, or F8
1194 * that are used for languages other than English.
1197 for (ptr
= option
->text
; *ptr
; ptr
++)
1198 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1199 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1204 if (!errors
&& !verbose
)
1205 _cupsLangPuts(stdout
, _(" FAIL\n"));
1208 _cupsLangPrintf(stdout
,
1209 _(" **FAIL** Default translation "
1210 "string for option %s contains 8-bit "
1217 for (j
= 0; j
< option
->num_choices
; j
++)
1220 * Check for special characters outside A0 to BF, F7, or F8
1221 * that are used for languages other than English.
1224 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1225 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1226 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1231 if (!errors
&& !verbose
)
1232 _cupsLangPuts(stdout
, _(" FAIL\n"));
1235 _cupsLangPrintf(stdout
,
1236 _(" **FAIL** Default translation "
1237 "string for option %s choice %s contains "
1238 "8-bit characters\n"),
1240 option
->choices
[j
].choice
);
1250 * Final pass/fail notification...
1254 status
= ERROR_CONFORMANCE
;
1256 _cupsLangPuts(stdout
, _(" PASS\n"));
1260 check_basics(argv
[i
]);
1262 if (warn
& WARN_DEFAULTS
)
1263 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1265 if (warn
& WARN_CONSTRAINTS
)
1266 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1268 if ((warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1269 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1271 if ((warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1272 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1274 if (warn
& WARN_SIZES
)
1275 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1277 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1279 if (warn
& WARN_TRANSLATIONS
)
1280 errors
= check_translations(ppd
, errors
, verbose
, 1);
1282 if (warn
& WARN_DUPLEX
)
1283 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1286 * Look for legacy duplex keywords...
1289 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1290 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1291 option
= ppdFindOption(ppd
, "KD03Duplex");
1294 _cupsLangPrintf(stdout
,
1295 _(" WARN Duplex option keyword %s may not "
1296 "work as expected and should be named Duplex\n"
1297 " REF: Page 122, section 5.17\n"),
1301 * Look for default keywords with no corresponding option...
1304 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1306 attr
= ppd
->attrs
[j
];
1308 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1309 !strcmp(attr
->name
, "DefaultColorSep") ||
1310 !strcmp(attr
->name
, "DefaultFont") ||
1311 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1312 !strcmp(attr
->name
, "DefaultImageableArea") ||
1313 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1314 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1315 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1316 !strcmp(attr
->name
, "DefaultResolution") ||
1317 !strcmp(attr
->name
, "DefaultScreenProc") ||
1318 !strcmp(attr
->name
, "DefaultTransfer"))
1321 if (!strncmp(attr
->name
, "Default", 7) &&
1322 !ppdFindOption(ppd
, attr
->name
+ 7))
1323 _cupsLangPrintf(stdout
,
1324 _(" WARN %s has no corresponding "
1329 ppdMarkDefaults(ppd
);
1330 if (ppdConflicts(ppd
))
1332 _cupsLangPuts(stdout
,
1333 _(" WARN Default choices conflicting\n"));
1335 show_conflicts(ppd
);
1338 if (ppdversion
< 43)
1340 _cupsLangPrintf(stdout
,
1341 _(" WARN Obsolete PPD version %.1f\n"
1342 " REF: Page 42, section 5.2.\n"),
1346 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1348 _cupsLangPuts(stdout
,
1349 _(" WARN LanguageEncoding required by PPD "
1351 " REF: Pages 56-57, section 5.3.\n"));
1354 if (!ppd
->manufacturer
&& ppdversion
< 43)
1356 _cupsLangPuts(stdout
,
1357 _(" WARN Manufacturer required by PPD "
1359 " REF: Pages 58-59, section 5.3.\n"));
1363 * Treat a PCFileName attribute longer than 12 characters as
1364 * a warning and not a hard error...
1367 if (!(ignore
& WARN_FILENAME
) && ppd
->pcfilename
)
1369 if (strlen(ppd
->pcfilename
) > 12)
1371 _cupsLangPuts(stdout
,
1372 _(" WARN PCFileName longer than 8.3 in "
1373 "violation of PPD spec.\n"
1374 " REF: Pages 61-62, section "
1378 if (!strcasecmp(ppd
->pcfilename
, "unused.ppd"))
1379 _cupsLangPuts(stdout
,
1380 _(" WARN PCFileName should contain a "
1381 "unique filename.\n"
1382 " REF: Pages 61-62, section "
1386 if (!ppd
->shortnickname
&& ppdversion
< 43)
1388 _cupsLangPuts(stdout
,
1389 _(" WARN ShortNickName required by PPD "
1391 " REF: Pages 64-65, section 5.3.\n"));
1395 * Check the Protocols line and flag PJL + BCP since TBCP is
1396 * usually used with PJL...
1401 if (strstr(ppd
->protocols
, "PJL") &&
1402 strstr(ppd
->protocols
, "BCP") &&
1403 !strstr(ppd
->protocols
, "TBCP"))
1405 _cupsLangPuts(stdout
,
1406 _(" WARN Protocols contains both PJL "
1407 "and BCP; expected TBCP.\n"
1408 " REF: Pages 78-79, section 5.7.\n"));
1411 if (strstr(ppd
->protocols
, "PJL") &&
1412 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1414 _cupsLangPuts(stdout
,
1415 _(" WARN Protocols contains PJL but JCL "
1416 "attributes are not set.\n"
1417 " REF: Pages 78-79, section 5.7.\n"));
1422 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1423 * which are errors according to the spec but won't cause problems
1424 * with CUPS specifically...
1427 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1428 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1430 len
= (int)strlen(option
->keyword
);
1432 for (m
= 0, group2
= ppd
->groups
;
1433 m
< ppd
->num_groups
;
1435 for (n
= 0, option2
= group2
->options
;
1436 n
< group2
->num_options
;
1438 if (option
!= option2
&&
1439 len
< (int)strlen(option2
->keyword
) &&
1440 !strncmp(option
->keyword
, option2
->keyword
, len
))
1442 _cupsLangPrintf(stdout
,
1443 _(" WARN %s shares a common "
1445 " REF: Page 15, section "
1447 option
->keyword
, option2
->keyword
);
1455 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1457 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1461 * Then list the options, if "-v" was provided...
1466 _cupsLangPrintf(stdout
,
1468 " language_level = %d\n"
1469 " color_device = %s\n"
1470 " variable_sizes = %s\n"
1471 " landscape = %d\n",
1472 ppd
->language_level
,
1473 ppd
->color_device
? "TRUE" : "FALSE",
1474 ppd
->variable_sizes
? "TRUE" : "FALSE",
1477 switch (ppd
->colorspace
)
1480 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1483 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1486 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1489 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1492 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1496 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1497 ppd
->num_emulations
);
1498 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1499 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1500 j
, ppd
->emulations
[j
].name
);
1502 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1503 ppd
->lang_encoding
);
1504 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1506 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1507 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1508 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1509 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1511 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1512 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1513 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1514 ppd
->shortnickname
);
1515 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1516 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1518 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1519 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1521 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1524 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1526 _cupsLangPrintf(stdout
,
1527 " options[%d] = %s (%s) %s %s %.0f "
1529 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1530 sections
[option
->section
], option
->order
,
1531 option
->num_choices
);
1533 if (!strcmp(option
->keyword
, "PageSize") ||
1534 !strcmp(option
->keyword
, "PageRegion"))
1536 for (m
= option
->num_choices
, choice
= option
->choices
;
1540 size
= ppdPageSize(ppd
, choice
->choice
);
1543 _cupsLangPrintf(stdout
,
1545 choice
->choice
, choice
->text
);
1547 _cupsLangPrintf(stdout
,
1548 " %s (%s) = %.2fx%.2fin "
1549 "(%.1f,%.1f,%.1f,%.1f)",
1550 choice
->choice
, choice
->text
,
1551 size
->width
/ 72.0, size
->length
/ 72.0,
1552 size
->left
/ 72.0, size
->bottom
/ 72.0,
1553 size
->right
/ 72.0, size
->top
/ 72.0);
1555 if (!strcmp(option
->defchoice
, choice
->choice
))
1556 _cupsLangPuts(stdout
, " *\n");
1558 _cupsLangPuts(stdout
, "\n");
1563 for (m
= option
->num_choices
, choice
= option
->choices
;
1567 _cupsLangPrintf(stdout
, " %s (%s)",
1568 choice
->choice
, choice
->text
);
1570 if (!strcmp(option
->defchoice
, choice
->choice
))
1571 _cupsLangPuts(stdout
, " *\n");
1573 _cupsLangPuts(stdout
, "\n");
1579 _cupsLangPrintf(stdout
, " num_consts = %d\n",
1581 for (j
= 0; j
< ppd
->num_consts
; j
++)
1582 _cupsLangPrintf(stdout
,
1583 " consts[%d] = *%s %s *%s %s\n",
1584 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1585 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1587 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1589 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1590 _cupsLangPrintf(stdout
,
1591 " profiles[%d] = %s/%s %.3f %.3f "
1592 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1593 j
, ppd
->profiles
[j
].resolution
,
1594 ppd
->profiles
[j
].media_type
,
1595 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1596 ppd
->profiles
[j
].matrix
[0][0],
1597 ppd
->profiles
[j
].matrix
[0][1],
1598 ppd
->profiles
[j
].matrix
[0][2],
1599 ppd
->profiles
[j
].matrix
[1][0],
1600 ppd
->profiles
[j
].matrix
[1][1],
1601 ppd
->profiles
[j
].matrix
[1][2],
1602 ppd
->profiles
[j
].matrix
[2][0],
1603 ppd
->profiles
[j
].matrix
[2][1],
1604 ppd
->profiles
[j
].matrix
[2][2]);
1606 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1607 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1608 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1611 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1612 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1613 _cupsLangPrintf(stdout
,
1614 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1615 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1616 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1617 ppd
->attrs
[j
]->text
,
1618 ppd
->attrs
[j
]->value
?
1619 ppd
->attrs
[j
]->value
: "(null)");
1633 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1637 check_basics(const char *filename
) /* I - PPD file to check */
1639 cups_file_t
*fp
; /* File pointer */
1640 int ch
; /* Current character */
1641 int col
, /* Current column */
1642 whitespace
; /* Only seen whitespace? */
1643 int eol
; /* Line endings */
1644 int linenum
; /* Line number */
1645 int mixed
; /* Mixed line endings? */
1648 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1657 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1659 if (ch
== '\r' || ch
== '\n')
1663 if (eol
== EOL_NONE
)
1665 else if (eol
!= EOL_LF
)
1668 else if (ch
== '\r')
1670 if (cupsFilePeekChar(fp
) == '\n')
1672 cupsFileGetChar(fp
);
1674 if (eol
== EOL_NONE
)
1676 else if (eol
!= EOL_CRLF
)
1679 else if (eol
== EOL_NONE
)
1681 else if (eol
!= EOL_CR
)
1685 if (col
> 0 && whitespace
)
1686 _cupsLangPrintf(stdout
,
1687 _(" WARN Line %d only contains whitespace\n"),
1696 if (ch
!= ' ' && ch
!= '\t')
1704 _cupsLangPuts(stdout
,
1705 _(" WARN File contains a mix of CR, LF, and "
1706 "CR LF line endings\n"));
1708 if (eol
== EOL_CRLF
)
1709 _cupsLangPuts(stdout
,
1710 _(" WARN Non-Windows PPD files should use lines "
1711 "ending with only LF, not CR LF\n"));
1718 * 'check_constraints()' - Check UIConstraints in the PPD file.
1721 static int /* O - Errors found */
1722 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1723 int errors
, /* I - Errors found */
1724 int verbose
, /* I - Verbosity level */
1725 int warn
) /* I - Warnings only? */
1727 int i
; /* Looping var */
1728 const char *prefix
; /* WARN/FAIL prefix */
1729 ppd_const_t
*c
; /* Current UIConstraints data */
1730 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1731 const char *vptr
; /* Pointer into constraint value */
1732 char option
[PPD_MAX_NAME
],
1733 /* Option name/MainKeyword */
1734 choice
[PPD_MAX_NAME
],
1735 /* Choice/OptionKeyword */
1736 *ptr
; /* Pointer into option or choice */
1737 int num_options
; /* Number of options */
1738 cups_option_t
*options
; /* Options */
1739 ppd_option_t
*o
; /* PPD option */
1742 prefix
= warn
? " WARN " : "**FAIL**";
1746 * See what kind of constraint data we have in the PPD...
1749 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1752 * Check new-style cupsUIConstraints data...
1756 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1758 if (!constattr
->value
)
1760 if (!warn
&& !errors
&& !verbose
)
1761 _cupsLangPuts(stdout
, _(" FAIL\n"));
1763 _cupsLangPrintf(stdout
,
1764 _(" %s Empty cupsUIConstraints %s\n"),
1765 prefix
, constattr
->spec
);
1773 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1775 i
++, vptr
= strchr(vptr
+ 1, '*'));
1779 if (!warn
&& !errors
&& !verbose
)
1780 _cupsLangPuts(stdout
, _(" FAIL\n"));
1782 _cupsLangPrintf(stdout
,
1783 _(" %s Bad cupsUIConstraints %s: \"%s\"\n"),
1784 prefix
, constattr
->spec
, constattr
->value
);
1792 cupsArraySave(ppd
->sorted_attrs
);
1794 if (constattr
->spec
[0] &&
1795 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1797 if (!warn
&& !errors
&& !verbose
)
1798 _cupsLangPuts(stdout
, _(" FAIL\n"));
1800 _cupsLangPrintf(stdout
,
1801 _(" %s Missing cupsUIResolver %s\n"),
1802 prefix
, constattr
->spec
);
1808 cupsArrayRestore(ppd
->sorted_attrs
);
1813 for (vptr
= strchr(constattr
->value
, '*');
1815 vptr
= strchr(vptr
, '*'))
1818 * Extract "*Option Choice" or just "*Option"...
1821 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1822 if (ptr
< (option
+ sizeof(option
) - 1))
1827 while (isspace(*vptr
& 255))
1834 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1835 if (ptr
< (choice
+ sizeof(choice
) - 1))
1841 if (!strncasecmp(option
, "Custom", 6) && !strcasecmp(choice
, "True"))
1843 _cups_strcpy(option
, option
+ 6);
1844 strcpy(choice
, "Custom");
1847 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1849 if (!warn
&& !errors
&& !verbose
)
1850 _cupsLangPuts(stdout
, _(" FAIL\n"));
1852 _cupsLangPrintf(stdout
,
1853 _(" %s Missing option %s in "
1854 "cupsUIConstraints %s: \"%s\"\n"),
1855 prefix
, option
, constattr
->spec
, constattr
->value
);
1863 if (choice
[0] && !ppdFindChoice(o
, choice
))
1865 if (!warn
&& !errors
&& !verbose
)
1866 _cupsLangPuts(stdout
, _(" FAIL\n"));
1868 _cupsLangPrintf(stdout
,
1869 _(" %s Missing choice *%s %s in "
1870 "cupsUIConstraints %s: \"%s\"\n"),
1871 prefix
, option
, choice
, constattr
->spec
,
1881 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1884 for (i
= 0; i
< o
->num_choices
; i
++)
1885 if (strcasecmp(o
->choices
[i
].choice
, "None") &&
1886 strcasecmp(o
->choices
[i
].choice
, "Off") &&
1887 strcasecmp(o
->choices
[i
].choice
, "False"))
1889 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
1890 num_options
, &options
);
1897 * Resolvers must list at least two options...
1900 if (num_options
< 2)
1902 if (!warn
&& !errors
&& !verbose
)
1903 _cupsLangPuts(stdout
, _(" FAIL\n"));
1905 _cupsLangPrintf(stdout
,
1906 _(" %s cupsUIResolver %s does not list at least "
1907 "two different options\n"),
1908 prefix
, constattr
->spec
);
1915 * Test the resolver...
1918 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
1920 if (!warn
&& !errors
&& !verbose
)
1921 _cupsLangPuts(stdout
, _(" FAIL\n"));
1923 _cupsLangPrintf(stdout
,
1924 _(" %s cupsUIResolver %s causes a loop\n"),
1925 prefix
, constattr
->spec
);
1931 cupsFreeOptions(num_options
, options
);
1937 * Check old-style [Non]UIConstraints data...
1940 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1942 if (!strncasecmp(c
->option1
, "Custom", 6) &&
1943 !strcasecmp(c
->choice1
, "True"))
1945 strcpy(option
, c
->option1
+ 6);
1946 strcpy(choice
, "Custom");
1950 strcpy(option
, c
->option1
);
1951 strcpy(choice
, c
->choice1
);
1954 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1956 if (!warn
&& !errors
&& !verbose
)
1957 _cupsLangPuts(stdout
, _(" FAIL\n"));
1959 _cupsLangPrintf(stdout
,
1960 _(" %s Missing option %s in "
1961 "UIConstraints \"*%s %s *%s %s\"\n"),
1963 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1968 else if (choice
[0] && !ppdFindChoice(o
, choice
))
1970 if (!warn
&& !errors
&& !verbose
)
1971 _cupsLangPuts(stdout
, _(" FAIL\n"));
1973 _cupsLangPrintf(stdout
,
1974 _(" %s Missing choice *%s %s in "
1975 "UIConstraints \"*%s %s *%s %s\"\n"),
1976 prefix
, c
->option1
, c
->choice1
,
1977 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1983 if (!strncasecmp(c
->option2
, "Custom", 6) &&
1984 !strcasecmp(c
->choice2
, "True"))
1986 strcpy(option
, c
->option2
+ 6);
1987 strcpy(choice
, "Custom");
1991 strcpy(option
, c
->option2
);
1992 strcpy(choice
, c
->choice2
);
1995 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1997 if (!warn
&& !errors
&& !verbose
)
1998 _cupsLangPuts(stdout
, _(" FAIL\n"));
2000 _cupsLangPrintf(stdout
,
2001 _(" %s Missing option %s in "
2002 "UIConstraints \"*%s %s *%s %s\"\n"),
2004 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2009 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2011 if (!warn
&& !errors
&& !verbose
)
2012 _cupsLangPuts(stdout
, _(" FAIL\n"));
2014 _cupsLangPrintf(stdout
,
2015 _(" %s Missing choice *%s %s in "
2016 "UIConstraints \"*%s %s *%s %s\"\n"),
2017 prefix
, c
->option2
, c
->choice2
,
2018 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2031 * 'check_case()' - Check that there are no duplicate groups, options,
2032 * or choices that differ only by case.
2035 static int /* O - Errors found */
2036 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2037 int errors
, /* I - Errors found */
2038 int verbose
) /* I - Verbosity level */
2040 int i
, j
; /* Looping vars */
2041 ppd_group_t
*groupa
, /* First group */
2042 *groupb
; /* Second group */
2043 ppd_option_t
*optiona
, /* First option */
2044 *optionb
; /* Second option */
2045 ppd_choice_t
*choicea
, /* First choice */
2046 *choiceb
; /* Second choice */
2050 * Check that the groups do not have any duplicate names...
2053 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2054 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2055 if (!strcasecmp(groupa
->name
, groupb
->name
))
2057 if (!errors
&& !verbose
)
2058 _cupsLangPuts(stdout
, _(" FAIL\n"));
2061 _cupsLangPrintf(stdout
,
2062 _(" **FAIL** Group names %s and %s differ only "
2064 groupa
->name
, groupb
->name
);
2070 * Check that the options do not have any duplicate names...
2073 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2075 cupsArraySave(ppd
->options
);
2076 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2077 if (!strcasecmp(optiona
->keyword
, optionb
->keyword
))
2079 if (!errors
&& !verbose
)
2080 _cupsLangPuts(stdout
, _(" FAIL\n"));
2083 _cupsLangPrintf(stdout
,
2084 _(" **FAIL** Option names %s and %s differ only "
2086 optiona
->keyword
, optionb
->keyword
);
2090 cupsArrayRestore(ppd
->options
);
2093 * Then the choices...
2096 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2099 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2100 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2102 if (!errors
&& !verbose
)
2103 _cupsLangPuts(stdout
, _(" FAIL\n"));
2106 _cupsLangPrintf(stdout
,
2107 _(" **FAIL** Multiple occurrences of %s "
2108 "choice name %s\n"),
2109 optiona
->keyword
, choicea
->choice
);
2117 else if (!strcasecmp(choicea
->choice
, choiceb
->choice
))
2119 if (!errors
&& !verbose
)
2120 _cupsLangPuts(stdout
, _(" FAIL\n"));
2123 _cupsLangPrintf(stdout
,
2124 _(" **FAIL** %s choice names %s and %s "
2125 "differ only by case\n"),
2126 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2133 * Return the number of errors found...
2141 * 'check_defaults()' - Check default option keywords in the PPD file.
2144 static int /* O - Errors found */
2145 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2146 int errors
, /* I - Errors found */
2147 int verbose
, /* I - Verbosity level */
2148 int warn
) /* I - Warnings only? */
2150 int j
, k
; /* Looping vars */
2151 ppd_attr_t
*attr
; /* PPD attribute */
2152 ppd_option_t
*option
; /* Standard UI option */
2153 const char *prefix
; /* WARN/FAIL prefix */
2156 prefix
= warn
? " WARN " : "**FAIL**";
2158 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2160 attr
= ppd
->attrs
[j
];
2162 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2163 !strcmp(attr
->name
, "DefaultFont") ||
2164 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2165 !strcmp(attr
->name
, "DefaultImageableArea") ||
2166 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2167 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2168 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2169 !strcmp(attr
->name
, "DefaultResolution") ||
2170 !strcmp(attr
->name
, "DefaultTransfer"))
2173 if (!strncmp(attr
->name
, "Default", 7))
2175 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2176 strcmp(attr
->value
, "Unknown"))
2179 * Check that the default option value matches a choice...
2182 for (k
= 0; k
< option
->num_choices
; k
++)
2183 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2186 if (k
>= option
->num_choices
)
2188 if (!warn
&& !errors
&& !verbose
)
2189 _cupsLangPuts(stdout
, _(" FAIL\n"));
2192 _cupsLangPrintf(stdout
,
2193 _(" %s %s %s does not exist\n"),
2194 prefix
, attr
->name
, attr
->value
);
2208 * 'check_duplex()' - Check duplex keywords in the PPD file.
2211 static int /* O - Errors found */
2212 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2213 int errors
, /* I - Error found */
2214 int verbose
, /* I - Verbosity level */
2215 int warn
) /* I - Warnings only? */
2217 int i
; /* Looping var */
2218 ppd_option_t
*option
; /* PPD option */
2219 ppd_choice_t
*choice
; /* Current choice */
2220 const char *prefix
; /* Message prefix */
2223 prefix
= warn
? " WARN " : "**FAIL**";
2226 * Check for a duplex option, and for standard values...
2229 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2231 if (!ppdFindChoice(option
, "None"))
2235 if (!warn
&& !errors
&& !verbose
)
2236 _cupsLangPuts(stdout
, _(" FAIL\n"));
2238 _cupsLangPrintf(stdout
,
2239 _(" %s REQUIRED %s does not define "
2241 " REF: Page 122, section 5.17\n"),
2242 prefix
, option
->keyword
);
2249 for (i
= option
->num_choices
, choice
= option
->choices
;
2252 if (strcmp(choice
->choice
, "None") &&
2253 strcmp(choice
->choice
, "DuplexNoTumble") &&
2254 strcmp(choice
->choice
, "DuplexTumble") &&
2255 strcmp(choice
->choice
, "SimplexTumble"))
2259 if (!warn
&& !errors
&& !verbose
)
2260 _cupsLangPuts(stdout
, _(" FAIL\n"));
2262 _cupsLangPrintf(stdout
,
2263 _(" %s Bad %s choice %s\n"
2264 " REF: Page 122, section 5.17\n"),
2265 prefix
, option
->keyword
, choice
->choice
);
2278 * 'check_filters()' - Check filters in the PPD file.
2281 static int /* O - Errors found */
2282 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2283 const char *root
, /* I - Root directory */
2284 int errors
, /* I - Errors found */
2285 int verbose
, /* I - Verbosity level */
2286 int warn
) /* I - Warnings only? */
2288 int i
; /* Looping var */
2289 ppd_attr_t
*attr
; /* PPD attribute */
2290 const char *ptr
; /* Pointer into string */
2291 char super
[16], /* Super-type for filter */
2292 type
[256], /* Type for filter */
2293 program
[1024], /* Program/filter name */
2294 pathprog
[1024]; /* Complete path to program/filter */
2295 int cost
; /* Cost of filter */
2296 const char *prefix
; /* WARN/FAIL prefix */
2297 struct stat fileinfo
; /* File information */
2300 prefix
= warn
? " WARN " : "**FAIL**";
2306 for (i
= 0; i
< ppd
->num_filters
; i
++)
2308 if (sscanf(ppd
->filters
[i
], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2309 &cost
, program
) != 4)
2311 if (!warn
&& !errors
&& !verbose
)
2312 _cupsLangPuts(stdout
, _(" FAIL\n"));
2315 _cupsLangPrintf(stdout
,
2316 _(" %s Bad cupsFilter value \"%s\"\n"),
2317 prefix
, ppd
->filters
[i
]);
2322 else if (strcmp(program
, "-"))
2324 if (program
[0] == '/')
2325 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2328 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2329 ptr
= CUPS_SERVERBIN
;
2331 if (*ptr
== '/' || !*root
)
2332 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2335 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2339 if (stat(pathprog
, &fileinfo
))
2341 if (!warn
&& !errors
&& !verbose
)
2342 _cupsLangPuts(stdout
, _(" FAIL\n"));
2345 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
2346 "file \"%s\"\n"), prefix
, pathprog
);
2351 else if (fileinfo
.st_uid
!= 0 ||
2352 (fileinfo
.st_mode
& MODE_WRITE
) ||
2353 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2355 if (!warn
&& !errors
&& !verbose
)
2356 _cupsLangPuts(stdout
, _(" FAIL\n"));
2359 _cupsLangPrintf(stdout
, _(" %s Bad permissions on cupsFilter "
2360 "file \"%s\"\n"), prefix
, pathprog
);
2366 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2374 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2376 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2378 if (strcmp(attr
->name
, "cupsPreFilter"))
2380 if (!warn
&& !errors
&& !verbose
)
2381 _cupsLangPuts(stdout
, _(" FAIL\n"));
2384 _cupsLangPrintf(stdout
,
2385 _(" %s Bad spelling of %s - should be %s\n"),
2386 prefix
, attr
->name
, "cupsPreFilter");
2393 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2394 &cost
, program
) != 4)
2396 if (!warn
&& !errors
&& !verbose
)
2397 _cupsLangPuts(stdout
, _(" FAIL\n"));
2400 _cupsLangPrintf(stdout
,
2401 _(" %s Bad cupsPreFilter value \"%s\"\n"),
2402 prefix
, attr
->value
? attr
->value
: "");
2407 else if (strcmp(program
, "-"))
2409 if (program
[0] == '/')
2410 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2413 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2414 ptr
= CUPS_SERVERBIN
;
2416 if (*ptr
== '/' || !*root
)
2417 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2420 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2424 if (stat(pathprog
, &fileinfo
))
2426 if (!warn
&& !errors
&& !verbose
)
2427 _cupsLangPuts(stdout
, _(" FAIL\n"));
2430 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
2431 "file \"%s\"\n"), prefix
, pathprog
);
2436 else if (fileinfo
.st_uid
!= 0 ||
2437 (fileinfo
.st_mode
& MODE_WRITE
) ||
2438 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2440 if (!warn
&& !errors
&& !verbose
)
2441 _cupsLangPuts(stdout
, _(" FAIL\n"));
2444 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2445 "cupsPreFilter file \"%s\"\n"), prefix
,
2452 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2461 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2463 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2465 if (strcmp(attr
->name
, "APDialogExtension"))
2467 if (!warn
&& !errors
&& !verbose
)
2468 _cupsLangPuts(stdout
, _(" FAIL\n"));
2471 _cupsLangPrintf(stdout
,
2472 _(" %s Bad spelling of %s - should be %s\n"),
2473 prefix
, attr
->name
, "APDialogExtension");
2479 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2480 attr
->value
? attr
->value
: "(null)");
2482 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2484 if (!warn
&& !errors
&& !verbose
)
2485 _cupsLangPuts(stdout
, _(" FAIL\n"));
2488 _cupsLangPrintf(stdout
, _(" %s Missing "
2489 "APDialogExtension file \"%s\"\n"),
2495 else if (fileinfo
.st_uid
!= 0 ||
2496 (fileinfo
.st_mode
& MODE_WRITE
) ||
2497 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2499 if (!warn
&& !errors
&& !verbose
)
2500 _cupsLangPuts(stdout
, _(" FAIL\n"));
2503 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2504 "APDialogExtension file \"%s\"\n"), prefix
,
2511 errors
= valid_path("APDialogExtension", pathprog
, errors
, verbose
,
2519 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2521 if (strcmp(attr
->name
, "APPrinterIconPath"))
2523 if (!warn
&& !errors
&& !verbose
)
2524 _cupsLangPuts(stdout
, _(" FAIL\n"));
2527 _cupsLangPrintf(stdout
,
2528 _(" %s Bad spelling of %s - should be %s\n"),
2529 prefix
, attr
->name
, "APPrinterIconPath");
2535 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2536 attr
->value
? attr
->value
: "(null)");
2538 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2540 if (!warn
&& !errors
&& !verbose
)
2541 _cupsLangPuts(stdout
, _(" FAIL\n"));
2544 _cupsLangPrintf(stdout
, _(" %s Missing "
2545 "APPrinterIconPath file \"%s\"\n"),
2551 else if (fileinfo
.st_uid
!= 0 ||
2552 (fileinfo
.st_mode
& MODE_WRITE
) ||
2553 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2555 if (!warn
&& !errors
&& !verbose
)
2556 _cupsLangPuts(stdout
, _(" FAIL\n"));
2559 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2560 "APPrinterIconPath file \"%s\"\n"), prefix
,
2567 errors
= valid_path("APPrinterIconPath", pathprog
, errors
, verbose
,
2572 * APPrinterLowInkTool
2575 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2577 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2579 if (!warn
&& !errors
&& !verbose
)
2580 _cupsLangPuts(stdout
, _(" FAIL\n"));
2583 _cupsLangPrintf(stdout
,
2584 _(" %s Bad spelling of %s - should be %s\n"),
2585 prefix
, attr
->name
, "APPrinterLowInkTool");
2591 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2592 attr
->value
? attr
->value
: "(null)");
2594 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2596 if (!warn
&& !errors
&& !verbose
)
2597 _cupsLangPuts(stdout
, _(" FAIL\n"));
2600 _cupsLangPrintf(stdout
, _(" %s Missing "
2601 "APPrinterLowInkTool file \"%s\"\n"),
2607 else if (fileinfo
.st_uid
!= 0 ||
2608 (fileinfo
.st_mode
& MODE_WRITE
) ||
2609 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2611 if (!warn
&& !errors
&& !verbose
)
2612 _cupsLangPuts(stdout
, _(" FAIL\n"));
2615 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2616 "APPrinterLowInkTool file \"%s\"\n"), prefix
,
2623 errors
= valid_path("APPrinterLowInkTool", pathprog
, errors
, verbose
,
2628 * APPrinterUtilityPath
2631 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2633 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2635 if (!warn
&& !errors
&& !verbose
)
2636 _cupsLangPuts(stdout
, _(" FAIL\n"));
2639 _cupsLangPrintf(stdout
,
2640 _(" %s Bad spelling of %s - should be %s\n"),
2641 prefix
, attr
->name
, "APPrinterUtilityPath");
2647 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2648 attr
->value
? attr
->value
: "(null)");
2650 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2652 if (!warn
&& !errors
&& !verbose
)
2653 _cupsLangPuts(stdout
, _(" FAIL\n"));
2656 _cupsLangPrintf(stdout
, _(" %s Missing "
2657 "APPrinterUtilityPath file \"%s\"\n"),
2663 else if (fileinfo
.st_uid
!= 0 ||
2664 (fileinfo
.st_mode
& MODE_WRITE
) ||
2665 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2667 if (!warn
&& !errors
&& !verbose
)
2668 _cupsLangPuts(stdout
, _(" FAIL\n"));
2671 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2672 "APPrinterUtilityPath file \"%s\"\n"), prefix
,
2679 errors
= valid_path("APPrinterUtilityPath", pathprog
, errors
, verbose
,
2684 * APScanAppBundleID and APScanAppPath
2687 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2689 if (strcmp(attr
->name
, "APScanAppPath"))
2691 if (!warn
&& !errors
&& !verbose
)
2692 _cupsLangPuts(stdout
, _(" FAIL\n"));
2695 _cupsLangPrintf(stdout
,
2696 _(" %s Bad spelling of %s - should be %s\n"),
2697 prefix
, attr
->name
, "APScanAppPath");
2703 if (!attr
->value
|| stat(attr
->value
, &fileinfo
))
2705 if (!warn
&& !errors
&& !verbose
)
2706 _cupsLangPuts(stdout
, _(" FAIL\n"));
2709 _cupsLangPrintf(stdout
, _(" %s Missing "
2710 "APScanAppPath file \"%s\"\n"),
2711 prefix
, attr
->value
? attr
->value
: "<NULL>");
2716 else if (fileinfo
.st_uid
!= 0 ||
2717 (fileinfo
.st_mode
& MODE_WRITE
) ||
2718 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2720 if (!warn
&& !errors
&& !verbose
)
2721 _cupsLangPuts(stdout
, _(" FAIL\n"));
2724 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2725 "APScanAppPath file \"%s\"\n"), prefix
,
2732 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2735 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2737 if (!warn
&& !errors
&& !verbose
)
2738 _cupsLangPuts(stdout
, _(" FAIL\n"));
2741 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2742 "APScanAppPath and APScanAppBundleID\n"),
2749 #endif /* __APPLE__ */
2756 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2759 static int /* O - Errors found */
2760 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2761 const char *root
, /* I - Root directory */
2762 int errors
, /* I - Errors found */
2763 int verbose
, /* I - Verbosity level */
2764 int warn
) /* I - Warnings only? */
2766 int i
; /* Looping var */
2767 ppd_attr_t
*attr
; /* PPD attribute */
2768 const char *ptr
; /* Pointer into string */
2769 const char *prefix
; /* WARN/FAIL prefix */
2770 char filename
[1024]; /* Profile filename */
2771 struct stat fileinfo
; /* File information */
2772 int num_profiles
= 0; /* Number of profiles */
2773 unsigned hash
, /* Current hash value */
2774 hashes
[1000]; /* Hash values of profile names */
2775 const char *specs
[1000]; /* Specifiers for profiles */
2778 prefix
= warn
? " WARN " : "**FAIL**";
2780 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
2782 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
2785 * Check for valid selector...
2788 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
2791 if (!attr
->value
|| i
< 2)
2793 if (!warn
&& !errors
&& !verbose
)
2794 _cupsLangPuts(stdout
, _(" FAIL\n"));
2797 _cupsLangPrintf(stdout
,
2798 _(" %s Bad cupsICCProfile %s\n"),
2799 prefix
, attr
->spec
);
2808 * Check for valid profile filename...
2811 if (attr
->value
[0] == '/')
2812 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
2815 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
2818 if (*ptr
== '/' || !*root
)
2819 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
2822 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
2826 if (stat(filename
, &fileinfo
))
2828 if (!warn
&& !errors
&& !verbose
)
2829 _cupsLangPuts(stdout
, _(" FAIL\n"));
2832 _cupsLangPrintf(stdout
, _(" %s Missing cupsICCProfile "
2833 "file \"%s\"\n"), prefix
, filename
);
2838 else if (fileinfo
.st_uid
!= 0 ||
2839 (fileinfo
.st_mode
& MODE_WRITE
) ||
2840 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2842 if (!warn
&& !errors
&& !verbose
)
2843 _cupsLangPuts(stdout
, _(" FAIL\n"));
2846 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2847 "cupsICCProfile file \"%s\"\n"), prefix
,
2854 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
2857 * Check for hash collisions...
2860 hash
= _ppdHashName(attr
->spec
);
2862 if (num_profiles
> 0)
2864 for (i
= 0; i
< num_profiles
; i
++)
2865 if (hashes
[i
] == hash
)
2868 if (i
< num_profiles
)
2870 if (!warn
&& !errors
&& !verbose
)
2871 _cupsLangPuts(stdout
, _(" FAIL\n"));
2874 _cupsLangPrintf(stdout
,
2875 _(" %s cupsICCProfile %s hash value "
2876 "collides with %s\n"), prefix
, attr
->spec
,
2885 * Remember up to 1000 profiles...
2888 if (num_profiles
< 1000)
2890 hashes
[num_profiles
] = hash
;
2891 specs
[num_profiles
] = attr
->spec
;
2901 * 'check_sizes()' - Check media sizes in the PPD file.
2904 static int /* O - Errors found */
2905 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
2906 int errors
, /* I - Errors found */
2907 int verbose
, /* I - Verbosity level */
2908 int warn
) /* I - Warnings only? */
2910 int i
; /* Looping vars */
2911 ppd_size_t
*size
; /* Current size */
2912 int width
, /* Custom width */
2913 length
; /* Custom length */
2914 char name
[PPD_MAX_NAME
], /* Size name without dot suffix */
2915 *nameptr
; /* Pointer into name */
2916 const char *prefix
; /* WARN/FAIL prefix */
2917 ppd_option_t
*page_size
, /* PageSize option */
2918 *page_region
; /* PageRegion option */
2921 prefix
= warn
? " WARN " : "**FAIL**";
2923 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
2925 if (!warn
&& !errors
&& !verbose
)
2926 _cupsLangPuts(stdout
, _(" FAIL\n"));
2929 _cupsLangPrintf(stdout
,
2930 _(" %s Missing REQUIRED PageSize option\n"
2931 " REF: Page 99, section 5.14.\n"),
2938 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
2940 if (!warn
&& !errors
&& !verbose
)
2941 _cupsLangPuts(stdout
, _(" FAIL\n"));
2944 _cupsLangPrintf(stdout
,
2945 _(" %s Missing REQUIRED PageRegion option\n"
2946 " REF: Page 100, section 5.14.\n"),
2953 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
2956 * Check that the size name is standard...
2959 if (!strcmp(size
->name
, "Custom"))
2962 * Skip custom page size...
2967 else if (warn
!= 2 && size
->name
[0] == 'w' &&
2968 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
2971 * Validate device-specific size wNNNhNNN should have proper width and
2975 if (fabs(width
- size
->width
) >= 1.0 ||
2976 fabs(length
- size
->length
) >= 1.0)
2978 if (!warn
&& !errors
&& !verbose
)
2979 _cupsLangPuts(stdout
, _(" FAIL\n"));
2982 _cupsLangPrintf(stdout
,
2983 _(" %s Size \"%s\" has unexpected dimensions "
2985 prefix
, size
->name
, size
->width
, size
->length
);
2993 * Verify that the size is defined for both PageSize and PageRegion...
2996 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
2998 if (!warn
&& !errors
&& !verbose
)
2999 _cupsLangPuts(stdout
, _(" FAIL\n"));
3002 _cupsLangPrintf(stdout
,
3003 _(" %s Size \"%s\" defined for %s but not for "
3005 prefix
, size
->name
, "PageRegion", "PageSize");
3010 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3012 if (!warn
&& !errors
&& !verbose
)
3013 _cupsLangPuts(stdout
, _(" FAIL\n"));
3016 _cupsLangPrintf(stdout
,
3017 _(" %s Size \"%s\" defined for %s but not for "
3019 prefix
, size
->name
, "PageSize", "PageRegion");
3031 * 'check_translations()' - Check translations in the PPD file.
3034 static int /* O - Errors found */
3035 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3036 int errors
, /* I - Errors found */
3037 int verbose
, /* I - Verbosity level */
3038 int warn
) /* I - Warnings only? */
3040 int j
; /* Looping var */
3041 ppd_attr_t
*attr
; /* PPD attribute */
3042 cups_array_t
*languages
; /* Array of languages */
3043 int langlen
; /* Length of language */
3044 char *language
, /* Current language */
3045 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3046 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3047 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3048 cllkeyword
[PPD_MAX_NAME
];
3049 /* Custom option keyword (base) */
3050 ppd_option_t
*option
; /* Standard UI option */
3051 ppd_coption_t
*coption
; /* Custom option */
3052 ppd_cparam_t
*cparam
; /* Custom parameter */
3053 char ll
[3]; /* Base language */
3054 const char *prefix
; /* WARN/FAIL prefix */
3055 const char *text
; /* Pointer into UI text */
3058 prefix
= warn
? " WARN " : "**FAIL**";
3060 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3063 * This file contains localizations, check them...
3066 for (language
= (char *)cupsArrayFirst(languages
);
3068 language
= (char *)cupsArrayNext(languages
))
3070 langlen
= (int)strlen(language
);
3071 if (langlen
!= 2 && langlen
!= 5)
3073 if (!warn
&& !errors
&& !verbose
)
3074 _cupsLangPuts(stdout
, _(" FAIL\n"));
3077 _cupsLangPrintf(stdout
,
3078 _(" %s Bad language \"%s\"\n"),
3087 if (!strcmp(language
, "en"))
3090 strlcpy(ll
, language
, sizeof(ll
));
3093 * Loop through all options and choices...
3096 for (option
= ppdFirstOption(ppd
);
3098 option
= ppdNextOption(ppd
))
3100 if (!strcmp(option
->keyword
, "PageRegion"))
3103 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3104 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3106 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3107 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3109 if (!warn
&& !errors
&& !verbose
)
3110 _cupsLangPuts(stdout
, _(" FAIL\n"));
3113 _cupsLangPrintf(stdout
,
3114 _(" %s Missing \"%s\" translation "
3115 "string for option %s\n"),
3116 prefix
, language
, option
->keyword
);
3121 else if (!valid_utf8(attr
->text
))
3123 if (!warn
&& !errors
&& !verbose
)
3124 _cupsLangPuts(stdout
, _(" FAIL\n"));
3127 _cupsLangPrintf(stdout
,
3128 _(" %s Bad UTF-8 \"%s\" translation "
3129 "string for option %s\n"),
3130 prefix
, language
, option
->keyword
);
3136 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3138 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3141 for (j
= 0; j
< option
->num_choices
; j
++)
3144 * First see if this choice is a number; if so, don't require
3148 for (text
= option
->choices
[j
].text
; *text
; text
++)
3149 if (!strchr("0123456789-+.", *text
))
3156 * Check custom choices differently...
3159 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3160 (coption
= ppdFindCustomOption(ppd
,
3161 option
->keyword
)) != NULL
)
3163 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3164 language
, option
->keyword
);
3166 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3167 !valid_utf8(attr
->text
))
3169 if (!warn
&& !errors
&& !verbose
)
3170 _cupsLangPuts(stdout
, _(" FAIL\n"));
3173 _cupsLangPrintf(stdout
,
3174 _(" %s Bad UTF-8 \"%s\" "
3175 "translation string for option %s, "
3178 ckeyword
+ 1 + strlen(language
),
3185 if (strcasecmp(option
->keyword
, "PageSize"))
3187 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3189 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3191 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3192 language
, option
->keyword
);
3193 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3194 ll
, option
->keyword
);
3196 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3197 cparam
->name
)) == NULL
&&
3198 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3199 cparam
->name
)) == NULL
)
3201 if (!warn
&& !errors
&& !verbose
)
3202 _cupsLangPuts(stdout
, _(" FAIL\n"));
3205 _cupsLangPrintf(stdout
,
3206 _(" %s Missing \"%s\" "
3207 "translation string for option %s, "
3210 ckeyword
+ 1 + strlen(language
),
3216 else if (!valid_utf8(attr
->text
))
3218 if (!warn
&& !errors
&& !verbose
)
3219 _cupsLangPuts(stdout
, _(" FAIL\n"));
3222 _cupsLangPrintf(stdout
,
3223 _(" %s Bad UTF-8 \"%s\" "
3224 "translation string for option %s, "
3227 ckeyword
+ 1 + strlen(language
),
3236 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3237 option
->choices
[j
].choice
)) == NULL
&&
3238 (attr
= ppdFindAttr(ppd
, llkeyword
,
3239 option
->choices
[j
].choice
)) == NULL
)
3241 if (!warn
&& !errors
&& !verbose
)
3242 _cupsLangPuts(stdout
, _(" FAIL\n"));
3245 _cupsLangPrintf(stdout
,
3246 _(" %s Missing \"%s\" "
3247 "translation string for option %s, "
3249 prefix
, language
, option
->keyword
,
3250 option
->choices
[j
].choice
);
3255 else if (!valid_utf8(attr
->text
))
3257 if (!warn
&& !errors
&& !verbose
)
3258 _cupsLangPuts(stdout
, _(" FAIL\n"));
3261 _cupsLangPrintf(stdout
,
3262 _(" %s Bad UTF-8 \"%s\" "
3263 "translation string for option %s, "
3265 prefix
, language
, option
->keyword
,
3266 option
->choices
[j
].choice
);
3276 * Verify that we have the base language for each localized one...
3279 for (language
= (char *)cupsArrayFirst(languages
);
3281 language
= (char *)cupsArrayNext(languages
))
3285 * Lookup the base language...
3288 cupsArraySave(languages
);
3290 strlcpy(ll
, language
, sizeof(ll
));
3292 if (!cupsArrayFind(languages
, ll
) &&
3293 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3295 if (!warn
&& !errors
&& !verbose
)
3296 _cupsLangPuts(stdout
, _(" FAIL\n"));
3299 _cupsLangPrintf(stdout
,
3300 _(" %s No base translation \"%s\" "
3301 "is included in file\n"), prefix
, ll
);
3307 cupsArrayRestore(languages
);
3311 * Free memory used for the languages...
3314 _ppdFreeLanguages(languages
);
3322 * 'show_conflicts()' - Show option conflicts in a PPD file.
3326 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
3328 int i
, j
; /* Looping variables */
3329 ppd_const_t
*c
; /* Current constraint */
3330 ppd_option_t
*o1
, *o2
; /* Options */
3331 ppd_choice_t
*c1
, *c2
; /* Choices */
3335 * Loop through all of the UI constraints and report any options
3339 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3342 * Grab pointers to the first option...
3345 o1
= ppdFindOption(ppd
, c
->option1
);
3349 else if (c
->choice1
[0] != '\0')
3352 * This constraint maps to a specific choice.
3355 c1
= ppdFindChoice(o1
, c
->choice1
);
3360 * This constraint applies to any choice for this option.
3363 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3368 !strcasecmp(c1
->choice
, "None") ||
3369 !strcasecmp(c1
->choice
, "Off") ||
3370 !strcasecmp(c1
->choice
, "False"))
3375 * Grab pointers to the second option...
3378 o2
= ppdFindOption(ppd
, c
->option2
);
3382 else if (c
->choice2
[0] != '\0')
3385 * This constraint maps to a specific choice.
3388 c2
= ppdFindChoice(o2
, c
->choice2
);
3393 * This constraint applies to any choice for this option.
3396 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3401 !strcasecmp(c2
->choice
, "None") ||
3402 !strcasecmp(c2
->choice
, "Off") ||
3403 !strcasecmp(c2
->choice
, "False"))
3408 * If both options are marked then there is a conflict...
3411 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3412 _cupsLangPrintf(stdout
,
3413 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
3414 " (constraint=\"%s %s %s %s\")\n"),
3415 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3416 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3422 * 'test_raster()' - Test PostScript commands for raster printers.
3425 static int /* O - 1 on success, 0 on failure */
3426 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3427 int verbose
) /* I - Verbosity */
3429 cups_page_header2_t header
; /* Page header */
3432 ppdMarkDefaults(ppd
);
3433 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3436 _cupsLangPuts(stdout
, _(" FAIL\n"));
3439 _cupsLangPrintf(stdout
,
3440 _(" **FAIL** Default option code cannot be "
3441 "interpreted: %s\n"), cupsRasterErrorString());
3447 * Try a test of custom page size code, if available...
3450 if (!ppdPageSize(ppd
, "Custom.612x792"))
3453 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3455 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3458 _cupsLangPuts(stdout
, _(" FAIL\n"));
3461 _cupsLangPrintf(stdout
,
3462 _(" **FAIL** Default option code cannot be "
3463 "interpreted: %s\n"), cupsRasterErrorString());
3473 * 'usage()' - Show program usage...
3479 _cupsLangPuts(stdout
,
3480 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
3481 "[... filenameN.ppd[.gz]]\n"
3482 " program | cupstestppd [options] -\n"
3486 " -I {filename,filters,none,profiles}\n"
3487 " Ignore specific warnings\n"
3488 " -R root-directory Set alternate root\n"
3489 " -W {all,none,constraints,defaults,duplex,filters,"
3490 "profiles,sizes,translations}\n"
3491 " Issue warnings instead of errors\n"
3492 " -q Run silently\n"
3493 " -r Use 'relaxed' open mode\n"
3494 " -v Be slightly verbose\n"
3495 " -vv Be very verbose\n"));
3502 * 'valid_path()' - Check whether a path has the correct capitalization.
3505 static int /* O - Errors found */
3506 valid_path(const char *keyword
, /* I - Keyword using path */
3507 const char *path
, /* I - Path to check */
3508 int errors
, /* I - Errors found */
3509 int verbose
, /* I - Verbosity level */
3510 int warn
) /* I - Warnings only? */
3512 cups_dir_t
*dir
; /* Current directory */
3513 cups_dentry_t
*dentry
; /* Current directory entry */
3514 char temp
[1024], /* Temporary path */
3515 *ptr
; /* Pointer into temporary path */
3516 const char *prefix
; /* WARN/FAIL prefix */
3519 prefix
= warn
? " WARN " : "**FAIL**";
3522 * Loop over the components of the path, checking that the entry exists with
3523 * the same capitalization...
3526 strlcpy(temp
, path
, sizeof(temp
));
3528 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3531 * Chop off the trailing component so temp == dirname and ptr == basename.
3537 * Try opening the directory containing the base name...
3541 dir
= cupsDirOpen(temp
);
3543 dir
= cupsDirOpen("/");
3549 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3551 if (!strcmp(dentry
->filename
, ptr
))
3559 * Display an error if the filename doesn't exist with the same
3565 if (!warn
&& !errors
&& !verbose
)
3566 _cupsLangPuts(stdout
, _(" FAIL\n"));
3569 _cupsLangPrintf(stdout
,
3570 _(" %s %s file \"%s\" has the wrong "
3571 "capitalization\n"), prefix
, keyword
, path
);
3585 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3588 static int /* O - 1 if valid, 0 if not */
3589 valid_utf8(const char *s
) /* I - String to check */
3596 * Check for valid UTF-8 sequence...
3599 if ((*s
& 0xc0) == 0x80)
3600 return (0); /* Illegal suffix byte */
3601 else if ((*s
& 0xe0) == 0xc0)
3604 * 2-byte sequence...
3609 if ((*s
& 0xc0) != 0x80)
3610 return (0); /* Missing suffix byte */
3612 else if ((*s
& 0xf0) == 0xe0)
3615 * 3-byte sequence...
3620 if ((*s
& 0xc0) != 0x80)
3621 return (0); /* Missing suffix byte */
3625 if ((*s
& 0xc0) != 0x80)
3626 return (0); /* Missing suffix byte */
3628 else if ((*s
& 0xf8) == 0xf0)
3631 * 4-byte sequence...
3636 if ((*s
& 0xc0) != 0x80)
3637 return (0); /* Missing suffix byte */
3641 if ((*s
& 0xc0) != 0x80)
3642 return (0); /* Missing suffix byte */
3646 if ((*s
& 0xc0) != 0x80)
3647 return (0); /* Missing suffix byte */
3650 return (0); /* Bad sequence */
3661 * End of "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $".