2 * PPD test program for CUPS.
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
13 * PostScript is a trademark of Adobe Systems, Inc.
15 * This file is subject to the Apple OS-Developed Software exception.
19 * Include necessary headers...
22 #include <cups/cups-private.h>
24 #include <cups/ppd-private.h>
25 #include <cups/raster.h>
33 * Error warning overrides...
43 WARN_TRANSLATIONS
= 16,
82 #define MODE_WRITE 0022 /* Group/other write */
83 #define MODE_MASK 0555 /* Owner/group/other read+exec/search */
84 #define MODE_DATAFILE 0444 /* Owner/group/other read */
85 #define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
86 #define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
93 static void check_basics(const char *filename
);
94 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
96 static int check_case(ppd_file_t
*ppd
, int errors
, int verbose
);
97 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
99 static int check_duplex(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_sizes(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
106 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,
108 static void show_conflicts(ppd_file_t
*ppd
, const char *prefix
);
109 static int test_raster(ppd_file_t
*ppd
, int verbose
);
110 static void usage(void) __attribute__((noreturn
));
111 static int valid_path(const char *keyword
, const char *path
, int errors
,
112 int verbose
, int warn
);
113 static int valid_utf8(const char *s
);
117 * 'main()' - Main entry for test program.
120 int /* O - Exit status */
121 main(int argc
, /* I - Number of command-line args */
122 char *argv
[]) /* I - Command-line arguments */
124 int i
, j
, k
, m
, n
; /* Looping vars */
125 size_t len
; /* Length of option name */
126 char *opt
; /* Option character */
127 const char *ptr
; /* Pointer into string */
128 cups_file_t
*fp
; /* PPD file */
129 int files
; /* Number of files */
130 int verbose
; /* Want verbose output? */
131 int warn
; /* Which errors to just warn about */
132 int ignore
; /* Which errors to ignore */
133 int status
; /* Exit status */
134 int errors
; /* Number of conformance errors */
135 int ppdversion
; /* PPD spec version in PPD file */
136 ppd_status_t error
; /* Status of ppdOpen*() */
137 int line
; /* Line number for error */
138 char *root
; /* Root directory */
139 int xdpi
, /* X resolution */
140 ydpi
; /* Y resolution */
141 ppd_file_t
*ppd
; /* PPD file record */
142 ppd_attr_t
*attr
; /* PPD attribute */
143 ppd_size_t
*size
; /* Size record */
144 ppd_group_t
*group
; /* UI group */
145 ppd_option_t
*option
; /* Standard UI option */
146 ppd_group_t
*group2
; /* UI group */
147 ppd_option_t
*option2
; /* Standard UI option */
148 ppd_choice_t
*choice
; /* Standard UI option choice */
149 struct lconv
*loc
; /* Locale data */
150 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
151 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
152 "JCL", "PAGE", "PROLOG" };
155 _cupsSetLocale(argv
);
159 * Display PPD files for each file listed on the command-line...
162 ppdSetConformance(PPD_CONFORM_STRICT
);
172 for (i
= 1; i
< argc
; i
++)
173 if (argv
[i
][0] == '-' && argv
[i
][1])
175 for (opt
= argv
[i
] + 1; *opt
; opt
++)
178 case 'I' : /* Ignore errors */
184 if (!strcmp(argv
[i
], "none"))
186 else if (!strcmp(argv
[i
], "filename"))
187 ignore
|= WARN_FILENAME
;
188 else if (!strcmp(argv
[i
], "filters"))
189 ignore
|= WARN_FILTERS
;
190 else if (!strcmp(argv
[i
], "profiles"))
191 ignore
|= WARN_PROFILES
;
192 else if (!strcmp(argv
[i
], "all"))
193 ignore
= WARN_FILTERS
| WARN_PROFILES
;
198 case 'R' : /* Alternate root directory */
207 case 'W' : /* Turn errors into warnings */
213 if (!strcmp(argv
[i
], "none"))
215 else if (!strcmp(argv
[i
], "constraints"))
216 warn
|= WARN_CONSTRAINTS
;
217 else if (!strcmp(argv
[i
], "defaults"))
218 warn
|= WARN_DEFAULTS
;
219 else if (!strcmp(argv
[i
], "duplex"))
221 else if (!strcmp(argv
[i
], "filters"))
222 warn
|= WARN_FILTERS
;
223 else if (!strcmp(argv
[i
], "profiles"))
224 warn
|= WARN_PROFILES
;
225 else if (!strcmp(argv
[i
], "sizes"))
227 else if (!strcmp(argv
[i
], "translations"))
228 warn
|= WARN_TRANSLATIONS
;
229 else if (!strcmp(argv
[i
], "all"))
235 case 'q' : /* Quiet mode */
238 _cupsLangPuts(stderr
,
239 _("cupstestppd: The -q option is incompatible "
240 "with the -v option."));
247 case 'r' : /* Relaxed mode */
248 ppdSetConformance(PPD_CONFORM_RELAXED
);
251 case 'v' : /* Verbose mode */
254 _cupsLangPuts(stderr
,
255 _("cupstestppd: The -v option is incompatible "
256 "with the -q option."));
271 * Open the PPD file...
274 if (files
&& verbose
>= 0)
279 if (argv
[i
][0] == '-')
285 ppd
= _ppdOpen(cupsFileStdin(), _PPD_LOCALIZATION_ALL
);
288 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
293 * Read from a file...
297 printf("%s:", argv
[i
]);
299 if ((fp
= cupsFileOpen(argv
[i
], "r")) != NULL
)
301 ppd
= _ppdOpen(fp
, _PPD_LOCALIZATION_ALL
);
306 status
= ERROR_FILE_OPEN
;
310 _cupsLangPuts(stdout
, _(" FAIL"));
311 _cupsLangPrintf(stdout
,
312 _(" **FAIL** Unable to open PPD file - %s on "
313 "line %d."), strerror(errno
), 0);
321 error
= ppdLastError(&line
);
323 if (error
<= PPD_ALLOC_ERROR
)
325 status
= ERROR_FILE_OPEN
;
329 _cupsLangPuts(stdout
, _(" FAIL"));
330 _cupsLangPrintf(stdout
,
331 _(" **FAIL** Unable to open PPD file - %s on "
332 "line %d."), strerror(errno
), 0);
337 status
= ERROR_PPD_FORMAT
;
341 _cupsLangPuts(stdout
, _(" FAIL"));
342 _cupsLangPrintf(stdout
,
343 _(" **FAIL** Unable to open PPD file - "
345 ppdErrorString(error
), line
);
349 case PPD_MISSING_PPDADOBE4
:
350 _cupsLangPuts(stdout
,
351 _(" REF: Page 42, section "
354 case PPD_MISSING_VALUE
:
355 _cupsLangPuts(stdout
,
356 _(" REF: Page 20, section "
359 case PPD_BAD_OPEN_GROUP
:
360 case PPD_NESTED_OPEN_GROUP
:
361 _cupsLangPuts(stdout
,
362 _(" REF: Pages 45-46, section "
365 case PPD_BAD_OPEN_UI
:
366 case PPD_NESTED_OPEN_UI
:
367 _cupsLangPuts(stdout
,
368 _(" REF: Pages 42-45, section "
371 case PPD_BAD_ORDER_DEPENDENCY
:
372 _cupsLangPuts(stdout
,
373 _(" REF: Pages 48-49, section "
376 case PPD_BAD_UI_CONSTRAINTS
:
377 _cupsLangPuts(stdout
,
378 _(" REF: Pages 52-54, section "
381 case PPD_MISSING_ASTERISK
:
382 _cupsLangPuts(stdout
,
383 _(" REF: Page 15, section "
386 case PPD_LINE_TOO_LONG
:
387 _cupsLangPuts(stdout
,
388 _(" REF: Page 15, section "
391 case PPD_ILLEGAL_CHARACTER
:
392 _cupsLangPuts(stdout
,
393 _(" REF: Page 15, section "
396 case PPD_ILLEGAL_MAIN_KEYWORD
:
397 _cupsLangPuts(stdout
,
398 _(" REF: Pages 16-17, section "
401 case PPD_ILLEGAL_OPTION_KEYWORD
:
402 _cupsLangPuts(stdout
,
403 _(" REF: Page 19, section "
406 case PPD_ILLEGAL_TRANSLATION
:
407 _cupsLangPuts(stdout
,
408 _(" REF: Page 27, section "
415 check_basics(argv
[i
]);
423 * Show the header and then perform basic conformance tests (limited
424 * only by what the CUPS PPD functions actually load...)
431 _cupsLangPuts(stdout
,
432 _("\n DETAILED CONFORMANCE TEST RESULTS"));
434 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
436 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
438 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) != NULL
)
442 if (strstr(attr
->value
, "application/vnd.cups-raster"))
444 if (!test_raster(ppd
, verbose
))
449 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
453 for (j
= 0; j
< ppd
->num_filters
; j
++)
454 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
456 if (!test_raster(ppd
, verbose
))
463 * Look for default keywords with no matching option...
466 if (!(warn
& WARN_DEFAULTS
))
467 errors
= check_defaults(ppd
, errors
, verbose
, 0);
469 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
473 if (!errors
&& !verbose
)
474 _cupsLangPuts(stdout
, _(" FAIL"));
476 _cupsLangPuts(stdout
,
477 _(" **FAIL** REQUIRED DefaultImageableArea\n"
478 " REF: Page 102, section 5.15."));
483 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
484 strcmp(attr
->value
, "Unknown"))
488 if (!errors
&& !verbose
)
489 _cupsLangPuts(stdout
, _(" FAIL"));
491 _cupsLangPrintf(stdout
,
492 _(" **FAIL** Bad DefaultImageableArea %s\n"
493 " REF: Page 102, section 5.15."),
502 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea"));
505 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
509 if (!errors
&& !verbose
)
510 _cupsLangPuts(stdout
, _(" FAIL"));
512 _cupsLangPuts(stdout
,
513 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
514 " REF: Page 103, section 5.15."));
519 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
520 strcmp(attr
->value
, "Unknown"))
524 if (!errors
&& !verbose
)
525 _cupsLangPuts(stdout
, _(" FAIL"));
527 _cupsLangPrintf(stdout
,
528 _(" **FAIL** Bad DefaultPaperDimension %s\n"
529 " REF: Page 103, section 5.15."),
535 else if (verbose
> 0)
536 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension"));
538 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
539 for (k
= 0, option
= group
->options
;
540 k
< group
->num_options
;
544 * Verify that we have a default choice...
547 if (option
->defchoice
[0])
549 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
550 strcmp(option
->defchoice
, "Unknown"))
554 if (!errors
&& !verbose
)
555 _cupsLangPuts(stdout
, _(" FAIL"));
557 _cupsLangPrintf(stdout
,
558 _(" **FAIL** Bad Default%s %s\n"
559 " REF: Page 40, section 4.5."),
560 option
->keyword
, option
->defchoice
);
565 else if (verbose
> 0)
566 _cupsLangPrintf(stdout
,
567 _(" PASS Default%s"),
574 if (!errors
&& !verbose
)
575 _cupsLangPuts(stdout
, _(" FAIL"));
577 _cupsLangPrintf(stdout
,
578 _(" **FAIL** REQUIRED Default%s\n"
579 " REF: Page 40, section 4.5."),
587 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
589 for (ptr
= attr
->value
; *ptr
; ptr
++)
590 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
597 if (!errors
&& !verbose
)
598 _cupsLangPuts(stdout
, _(" FAIL"));
600 _cupsLangPrintf(stdout
,
601 _(" **FAIL** Bad FileVersion \"%s\"\n"
602 " REF: Page 56, section 5.3."),
608 else if (verbose
> 0)
609 _cupsLangPuts(stdout
, _(" PASS FileVersion"));
615 if (!errors
&& !verbose
)
616 _cupsLangPuts(stdout
, _(" FAIL"));
618 _cupsLangPuts(stdout
,
619 _(" **FAIL** REQUIRED FileVersion\n"
620 " REF: Page 56, section 5.3."));
626 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
629 if (*ptr
== '4' && ptr
[1] == '.')
632 for (ptr
+= 2; *ptr
; ptr
++)
633 if (!isdigit(*ptr
& 255))
641 if (!errors
&& !verbose
)
642 _cupsLangPuts(stdout
, _(" FAIL"));
644 _cupsLangPrintf(stdout
,
645 _(" **FAIL** Bad FormatVersion \"%s\"\n"
646 " REF: Page 56, section 5.3."),
652 else if (verbose
> 0)
653 _cupsLangPuts(stdout
, _(" PASS FormatVersion"));
659 if (!errors
&& !verbose
)
660 _cupsLangPuts(stdout
, _(" FAIL"));
662 _cupsLangPuts(stdout
,
663 _(" **FAIL** REQUIRED FormatVersion\n"
664 " REF: Page 56, section 5.3."));
670 if (ppd
->lang_encoding
!= NULL
)
673 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding"));
675 else if (ppdversion
> 40)
679 if (!errors
&& !verbose
)
680 _cupsLangPuts(stdout
, _(" FAIL"));
682 _cupsLangPuts(stdout
,
683 _(" **FAIL** REQUIRED LanguageEncoding\n"
684 " REF: Pages 56-57, section 5.3."));
690 if (ppd
->lang_version
!= NULL
)
693 _cupsLangPuts(stdout
, _(" PASS LanguageVersion"));
699 if (!errors
&& !verbose
)
700 _cupsLangPuts(stdout
, _(" FAIL"));
702 _cupsLangPuts(stdout
,
703 _(" **FAIL** REQUIRED LanguageVersion\n"
704 " REF: Pages 57-58, section 5.3."));
710 if (ppd
->manufacturer
!= NULL
)
712 if (!_cups_strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
713 !_cups_strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
717 if (!errors
&& !verbose
)
718 _cupsLangPuts(stdout
, _(" FAIL"));
720 _cupsLangPrintf(stdout
,
721 _(" **FAIL** Bad Manufacturer (should be "
723 " REF: Page 211, table D.1."),
729 else if (!_cups_strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
730 !_cups_strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
734 if (!errors
&& !verbose
)
735 _cupsLangPuts(stdout
, _(" FAIL"));
737 _cupsLangPrintf(stdout
,
738 _(" **FAIL** Bad Manufacturer (should be "
740 " REF: Page 211, table D.1."),
746 else if (verbose
> 0)
747 _cupsLangPuts(stdout
, _(" PASS Manufacturer"));
749 else if (ppdversion
>= 43)
753 if (!errors
&& !verbose
)
754 _cupsLangPuts(stdout
, _(" FAIL"));
756 _cupsLangPuts(stdout
,
757 _(" **FAIL** REQUIRED Manufacturer\n"
758 " REF: Pages 58-59, section 5.3."));
764 if (ppd
->modelname
!= NULL
)
766 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
767 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
774 if (!errors
&& !verbose
)
775 _cupsLangPuts(stdout
, _(" FAIL"));
777 _cupsLangPrintf(stdout
,
778 _(" **FAIL** Bad ModelName - \"%c\" not "
779 "allowed in string.\n"
780 " REF: Pages 59-60, section 5.3."),
786 else if (verbose
> 0)
787 _cupsLangPuts(stdout
, _(" PASS ModelName"));
793 if (!errors
&& !verbose
)
794 _cupsLangPuts(stdout
, _(" FAIL"));
796 _cupsLangPuts(stdout
,
797 _(" **FAIL** REQUIRED ModelName\n"
798 " REF: Pages 59-60, section 5.3."));
804 if (ppd
->nickname
!= NULL
)
807 _cupsLangPuts(stdout
, _(" PASS NickName"));
813 if (!errors
&& !verbose
)
814 _cupsLangPuts(stdout
, _(" FAIL"));
816 _cupsLangPuts(stdout
,
817 _(" **FAIL** REQUIRED NickName\n"
818 " REF: Page 60, section 5.3."));
824 if (ppdFindOption(ppd
, "PageSize") != NULL
)
827 _cupsLangPuts(stdout
, _(" PASS PageSize"));
833 if (!errors
&& !verbose
)
834 _cupsLangPuts(stdout
, _(" FAIL"));
836 _cupsLangPuts(stdout
,
837 _(" **FAIL** REQUIRED PageSize\n"
838 " REF: Pages 99-100, section 5.14."));
844 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
847 _cupsLangPuts(stdout
, _(" PASS PageRegion"));
853 if (!errors
&& !verbose
)
854 _cupsLangPuts(stdout
, _(" FAIL"));
856 _cupsLangPuts(stdout
,
857 _(" **FAIL** REQUIRED PageRegion\n"
858 " REF: Page 100, section 5.14."));
864 if (ppd
->pcfilename
!= NULL
)
867 _cupsLangPuts(stdout
, _(" PASS PCFileName"));
869 else if (!(ignore
& WARN_FILENAME
))
873 if (!errors
&& !verbose
)
874 _cupsLangPuts(stdout
, _(" FAIL"));
876 _cupsLangPuts(stdout
,
877 _(" **FAIL** REQUIRED PCFileName\n"
878 " REF: Pages 61-62, section 5.3."));
884 if (ppd
->product
!= NULL
)
886 if (ppd
->product
[0] != '(' ||
887 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
891 if (!errors
&& !verbose
)
892 _cupsLangPuts(stdout
, _(" FAIL"));
894 _cupsLangPuts(stdout
,
895 _(" **FAIL** Bad Product - not \"(string)\".\n"
896 " REF: Page 62, section 5.3."));
901 else if (verbose
> 0)
902 _cupsLangPuts(stdout
, _(" PASS Product"));
908 if (!errors
&& !verbose
)
909 _cupsLangPuts(stdout
, _(" FAIL"));
911 _cupsLangPuts(stdout
,
912 _(" **FAIL** REQUIRED Product\n"
913 " REF: Page 62, section 5.3."));
919 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
922 char junkstr
[255]; /* Temp string */
923 int junkint
; /* Temp integer */
926 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
930 if (!errors
&& !verbose
)
931 _cupsLangPuts(stdout
, _(" FAIL"));
933 _cupsLangPuts(stdout
,
934 _(" **FAIL** Bad PSVersion - not \"(string) "
936 " REF: Pages 62-64, section 5.3."));
941 else if (verbose
> 0)
942 _cupsLangPuts(stdout
, _(" PASS PSVersion"));
948 if (!errors
&& !verbose
)
949 _cupsLangPuts(stdout
, _(" FAIL"));
951 _cupsLangPuts(stdout
,
952 _(" **FAIL** REQUIRED PSVersion\n"
953 " REF: Pages 62-64, section 5.3."));
959 if (ppd
->shortnickname
!= NULL
)
961 if (strlen(ppd
->shortnickname
) > 31)
965 if (!errors
&& !verbose
)
966 _cupsLangPuts(stdout
, _(" FAIL"));
968 _cupsLangPuts(stdout
,
969 _(" **FAIL** Bad ShortNickName - longer "
971 " REF: Pages 64-65, section 5.3."));
976 else if (verbose
> 0)
977 _cupsLangPuts(stdout
, _(" PASS ShortNickName"));
979 else if (ppdversion
>= 43)
983 if (!errors
&& !verbose
)
984 _cupsLangPuts(stdout
, _(" FAIL"));
986 _cupsLangPuts(stdout
,
987 _(" **FAIL** REQUIRED ShortNickName\n"
988 " REF: Page 64-65, section 5.3."));
994 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
995 strstr(ppd
->patches
, "*End"))
999 if (!errors
&& !verbose
)
1000 _cupsLangPuts(stdout
, _(" FAIL"));
1002 _cupsLangPuts(stdout
,
1003 _(" **FAIL** Bad JobPatchFile attribute in file\n"
1004 " REF: Page 24, section 3.4."));
1011 * Check for page sizes without the corresponding ImageableArea or
1012 * PaperDimension values...
1015 if (ppd
->num_sizes
== 0)
1019 if (!errors
&& !verbose
)
1020 _cupsLangPuts(stdout
, _(" FAIL"));
1022 _cupsLangPuts(stdout
,
1023 _(" **FAIL** REQUIRED PageSize\n"
1024 " REF: Page 41, section 5.\n"
1025 " REF: Page 99, section 5.14."));
1032 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1035 * Don't check custom size...
1038 if (!strcmp(size
->name
, "Custom"))
1042 * Check for ImageableArea...
1045 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1046 size
->right
== 0.0 && size
->top
== 0.0)
1050 if (!errors
&& !verbose
)
1051 _cupsLangPuts(stdout
, _(" FAIL"));
1053 _cupsLangPrintf(stdout
,
1054 _(" **FAIL** REQUIRED ImageableArea for "
1056 " REF: Page 41, section 5.\n"
1057 " REF: Page 102, section 5.15."),
1065 * Check for PaperDimension...
1068 if (size
->width
<= 0.0 && size
->length
<= 0.0)
1072 if (!errors
&& !verbose
)
1073 _cupsLangPuts(stdout
, _(" FAIL"));
1075 _cupsLangPrintf(stdout
,
1076 _(" **FAIL** REQUIRED PaperDimension "
1078 " REF: Page 41, section 5.\n"
1079 " REF: Page 103, section 5.15."),
1089 * Check for valid Resolution, JCLResolution, or SetResolution values...
1092 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1093 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1094 option
= ppdFindOption(ppd
, "SetResolution");
1098 for (j
= option
->num_choices
, choice
= option
->choices
;
1103 * Verify that all resolution options are of the form NNNdpi
1107 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1108 if (ptr
> choice
->choice
&& xdpi
> 0)
1111 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1118 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1123 if (!errors
&& !verbose
)
1124 _cupsLangPuts(stdout
, _(" FAIL"));
1126 _cupsLangPrintf(stdout
,
1127 _(" **FAIL** Bad option %s choice %s\n"
1128 " REF: Page 84, section 5.9"),
1129 option
->keyword
, choice
->choice
);
1137 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1138 strcmp(attr
->name
, "1284DeviceID"))
1142 if (!errors
&& !verbose
)
1143 _cupsLangPuts(stdout
, _(" FAIL"));
1145 _cupsLangPrintf(stdout
,
1146 _(" **FAIL** %s must be 1284DeviceID\n"
1147 " REF: Page 72, section 5.5"),
1154 errors
= check_case(ppd
, errors
, verbose
);
1156 if (!(warn
& WARN_CONSTRAINTS
))
1157 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1159 if (!(warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1160 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1162 if (!(warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1163 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1165 if (!(warn
& WARN_SIZES
))
1166 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1168 if (!(warn
& WARN_TRANSLATIONS
))
1169 errors
= check_translations(ppd
, errors
, verbose
, 0);
1171 if (!(warn
& WARN_DUPLEX
))
1172 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1174 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1178 * This file contains localizations, check for conformance of the
1179 * base translation...
1182 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1184 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1186 if (!errors
&& !verbose
)
1187 _cupsLangPuts(stdout
, _(" FAIL"));
1190 _cupsLangPrintf(stdout
,
1191 _(" **FAIL** Bad LanguageEncoding %s - "
1192 "must be ISOLatin1."),
1193 attr
->value
? attr
->value
: "(null)");
1198 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1200 if (!errors
&& !verbose
)
1201 _cupsLangPuts(stdout
, _(" FAIL"));
1204 _cupsLangPrintf(stdout
,
1205 _(" **FAIL** Bad LanguageVersion %s - "
1206 "must be English."),
1207 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1213 * Loop through all options and choices...
1216 for (option
= ppdFirstOption(ppd
);
1218 option
= ppdNextOption(ppd
))
1221 * Check for special characters outside A0 to BF, F7, or F8
1222 * that are used for languages other than English.
1225 for (ptr
= option
->text
; *ptr
; ptr
++)
1226 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1227 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1232 if (!errors
&& !verbose
)
1233 _cupsLangPuts(stdout
, _(" FAIL"));
1236 _cupsLangPrintf(stdout
,
1237 _(" **FAIL** Default translation "
1238 "string for option %s contains 8-bit "
1245 for (j
= 0; j
< option
->num_choices
; j
++)
1248 * Check for special characters outside A0 to BF, F7, or F8
1249 * that are used for languages other than English.
1252 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1253 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1254 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1259 if (!errors
&& !verbose
)
1260 _cupsLangPuts(stdout
, _(" FAIL"));
1263 _cupsLangPrintf(stdout
,
1264 _(" **FAIL** Default translation "
1265 "string for option %s choice %s contains "
1266 "8-bit characters."),
1268 option
->choices
[j
].choice
);
1278 * Final pass/fail notification...
1282 status
= ERROR_CONFORMANCE
;
1284 _cupsLangPuts(stdout
, _(" PASS"));
1288 check_basics(argv
[i
]);
1290 if (warn
& WARN_DEFAULTS
)
1291 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1293 if (warn
& WARN_CONSTRAINTS
)
1294 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1296 if ((warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1297 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1299 if ((warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1300 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1302 if (warn
& WARN_SIZES
)
1303 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1305 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1307 if (warn
& WARN_TRANSLATIONS
)
1308 errors
= check_translations(ppd
, errors
, verbose
, 1);
1310 if (warn
& WARN_DUPLEX
)
1311 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1314 * Look for legacy duplex keywords...
1317 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1318 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1319 option
= ppdFindOption(ppd
, "KD03Duplex");
1322 _cupsLangPrintf(stdout
,
1323 _(" WARN Duplex option keyword %s may not "
1324 "work as expected and should be named Duplex.\n"
1325 " REF: Page 122, section 5.17"),
1329 * Look for default keywords with no corresponding option...
1332 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1334 attr
= ppd
->attrs
[j
];
1336 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1337 !strcmp(attr
->name
, "DefaultColorSep") ||
1338 !strcmp(attr
->name
, "DefaultFont") ||
1339 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1340 !strcmp(attr
->name
, "DefaultImageableArea") ||
1341 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1342 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1343 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1344 !strcmp(attr
->name
, "DefaultResolution") ||
1345 !strcmp(attr
->name
, "DefaultScreenProc") ||
1346 !strcmp(attr
->name
, "DefaultTransfer"))
1349 if (!strncmp(attr
->name
, "Default", 7) &&
1350 !ppdFindOption(ppd
, attr
->name
+ 7))
1351 _cupsLangPrintf(stdout
,
1352 _(" WARN %s has no corresponding "
1357 if (ppdversion
< 43)
1359 _cupsLangPrintf(stdout
,
1360 _(" WARN Obsolete PPD version %.1f.\n"
1361 " REF: Page 42, section 5.2."),
1365 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1367 _cupsLangPuts(stdout
,
1368 _(" WARN LanguageEncoding required by PPD "
1370 " REF: Pages 56-57, section 5.3."));
1373 if (!ppd
->manufacturer
&& ppdversion
< 43)
1375 _cupsLangPuts(stdout
,
1376 _(" WARN Manufacturer required by PPD "
1378 " REF: Pages 58-59, section 5.3."));
1382 * Treat a PCFileName attribute longer than 12 characters as
1383 * a warning and not a hard error...
1386 if (!(ignore
& WARN_FILENAME
) && ppd
->pcfilename
)
1388 if (strlen(ppd
->pcfilename
) > 12)
1390 _cupsLangPuts(stdout
,
1391 _(" WARN PCFileName longer than 8.3 in "
1392 "violation of PPD spec.\n"
1393 " REF: Pages 61-62, section "
1397 if (!_cups_strcasecmp(ppd
->pcfilename
, "unused.ppd"))
1398 _cupsLangPuts(stdout
,
1399 _(" WARN PCFileName should contain a "
1400 "unique filename.\n"
1401 " REF: Pages 61-62, section "
1405 if (!ppd
->shortnickname
&& ppdversion
< 43)
1407 _cupsLangPuts(stdout
,
1408 _(" WARN ShortNickName required by PPD "
1410 " REF: Pages 64-65, section 5.3."));
1414 * Check the Protocols line and flag PJL + BCP since TBCP is
1415 * usually used with PJL...
1420 if (strstr(ppd
->protocols
, "PJL") &&
1421 strstr(ppd
->protocols
, "BCP") &&
1422 !strstr(ppd
->protocols
, "TBCP"))
1424 _cupsLangPuts(stdout
,
1425 _(" WARN Protocols contains both PJL "
1426 "and BCP; expected TBCP.\n"
1427 " REF: Pages 78-79, section 5.7."));
1430 if (strstr(ppd
->protocols
, "PJL") &&
1431 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1433 _cupsLangPuts(stdout
,
1434 _(" WARN Protocols contains PJL but JCL "
1435 "attributes are not set.\n"
1436 " REF: Pages 78-79, section 5.7."));
1441 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1442 * which are errors according to the spec but won't cause problems
1443 * with CUPS specifically...
1446 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1447 for (k
= 0, option
= group
->options
;
1448 k
< group
->num_options
;
1451 len
= strlen(option
->keyword
);
1453 for (m
= 0, group2
= ppd
->groups
;
1454 m
< ppd
->num_groups
;
1456 for (n
= 0, option2
= group2
->options
;
1457 n
< group2
->num_options
;
1459 if (option
!= option2
&&
1460 len
< strlen(option2
->keyword
) &&
1461 !strncmp(option
->keyword
, option2
->keyword
, len
))
1463 _cupsLangPrintf(stdout
,
1464 _(" WARN %s shares a common "
1466 " REF: Page 15, section "
1468 option
->keyword
, option2
->keyword
);
1476 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND"), errors
);
1478 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND"));
1482 * Then list the options, if "-v" was provided...
1487 _cupsLangPrintf(stdout
,
1489 " language_level = %d\n"
1490 " color_device = %s\n"
1491 " variable_sizes = %s\n"
1493 ppd
->language_level
,
1494 ppd
->color_device
? "TRUE" : "FALSE",
1495 ppd
->variable_sizes
? "TRUE" : "FALSE",
1498 switch (ppd
->colorspace
)
1501 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK");
1504 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY");
1507 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY");
1510 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB");
1513 _cupsLangPuts(stdout
, " colorspace = <unknown>");
1517 _cupsLangPrintf(stdout
, " num_emulations = %d",
1518 ppd
->num_emulations
);
1519 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1520 _cupsLangPrintf(stdout
, " emulations[%d] = %s",
1521 j
, ppd
->emulations
[j
].name
);
1523 _cupsLangPrintf(stdout
, " lang_encoding = %s",
1524 ppd
->lang_encoding
);
1525 _cupsLangPrintf(stdout
, " lang_version = %s",
1527 _cupsLangPrintf(stdout
, " modelname = %s", ppd
->modelname
);
1528 _cupsLangPrintf(stdout
, " ttrasterizer = %s",
1529 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1530 _cupsLangPrintf(stdout
, " manufacturer = %s",
1532 _cupsLangPrintf(stdout
, " product = %s", ppd
->product
);
1533 _cupsLangPrintf(stdout
, " nickname = %s", ppd
->nickname
);
1534 _cupsLangPrintf(stdout
, " shortnickname = %s",
1535 ppd
->shortnickname
);
1536 _cupsLangPrintf(stdout
, " patches = %d bytes",
1537 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1539 _cupsLangPrintf(stdout
, " num_groups = %d", ppd
->num_groups
);
1540 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1542 _cupsLangPrintf(stdout
, " group[%d] = %s",
1545 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1547 _cupsLangPrintf(stdout
,
1548 " options[%d] = %s (%s) %s %s %.0f "
1550 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1551 sections
[option
->section
], option
->order
,
1552 option
->num_choices
);
1554 if (!strcmp(option
->keyword
, "PageSize") ||
1555 !strcmp(option
->keyword
, "PageRegion"))
1557 for (m
= option
->num_choices
, choice
= option
->choices
;
1561 size
= ppdPageSize(ppd
, choice
->choice
);
1564 _cupsLangPrintf(stdout
,
1565 " %s (%s) = ERROR%s",
1566 choice
->choice
, choice
->text
,
1567 !strcmp(option
->defchoice
, choice
->choice
)
1570 _cupsLangPrintf(stdout
,
1571 " %s (%s) = %.2fx%.2fin "
1572 "(%.1f,%.1f,%.1f,%.1f)%s",
1573 choice
->choice
, choice
->text
,
1574 size
->width
/ 72.0, size
->length
/ 72.0,
1575 size
->left
/ 72.0, size
->bottom
/ 72.0,
1576 size
->right
/ 72.0, size
->top
/ 72.0,
1577 !strcmp(option
->defchoice
, choice
->choice
)
1583 for (m
= option
->num_choices
, choice
= option
->choices
;
1587 _cupsLangPrintf(stdout
, " %s (%s)%s",
1588 choice
->choice
, choice
->text
,
1589 !strcmp(option
->defchoice
, choice
->choice
)
1596 _cupsLangPrintf(stdout
, " num_consts = %d",
1598 for (j
= 0; j
< ppd
->num_consts
; j
++)
1599 _cupsLangPrintf(stdout
,
1600 " consts[%d] = *%s %s *%s %s",
1601 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1602 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1604 _cupsLangPrintf(stdout
, " num_profiles = %d",
1606 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1607 _cupsLangPrintf(stdout
,
1608 " profiles[%d] = %s/%s %.3f %.3f "
1609 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]",
1610 j
, ppd
->profiles
[j
].resolution
,
1611 ppd
->profiles
[j
].media_type
,
1612 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1613 ppd
->profiles
[j
].matrix
[0][0],
1614 ppd
->profiles
[j
].matrix
[0][1],
1615 ppd
->profiles
[j
].matrix
[0][2],
1616 ppd
->profiles
[j
].matrix
[1][0],
1617 ppd
->profiles
[j
].matrix
[1][1],
1618 ppd
->profiles
[j
].matrix
[1][2],
1619 ppd
->profiles
[j
].matrix
[2][0],
1620 ppd
->profiles
[j
].matrix
[2][1],
1621 ppd
->profiles
[j
].matrix
[2][2]);
1623 _cupsLangPrintf(stdout
, " num_fonts = %d", ppd
->num_fonts
);
1624 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1625 _cupsLangPrintf(stdout
, " fonts[%d] = %s",
1628 _cupsLangPrintf(stdout
, " num_attrs = %d", ppd
->num_attrs
);
1629 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1630 _cupsLangPrintf(stdout
,
1631 " attrs[%d] = %s %s%s%s: \"%s\"", j
,
1632 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1633 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1634 ppd
->attrs
[j
]->text
,
1635 ppd
->attrs
[j
]->value
?
1636 ppd
->attrs
[j
]->value
: "(null)");
1650 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1654 check_basics(const char *filename
) /* I - PPD file to check */
1656 cups_file_t
*fp
; /* File pointer */
1657 int ch
; /* Current character */
1658 int col
, /* Current column */
1659 whitespace
; /* Only seen whitespace? */
1660 int eol
; /* Line endings */
1661 int linenum
; /* Line number */
1662 int mixed
; /* Mixed line endings? */
1665 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1674 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1676 if (ch
== '\r' || ch
== '\n')
1680 if (eol
== EOL_NONE
)
1682 else if (eol
!= EOL_LF
)
1685 else if (ch
== '\r')
1687 if (cupsFilePeekChar(fp
) == '\n')
1689 cupsFileGetChar(fp
);
1691 if (eol
== EOL_NONE
)
1693 else if (eol
!= EOL_CRLF
)
1696 else if (eol
== EOL_NONE
)
1698 else if (eol
!= EOL_CR
)
1702 if (col
> 0 && whitespace
)
1703 _cupsLangPrintf(stdout
,
1704 _(" WARN Line %d only contains whitespace."),
1713 if (ch
!= ' ' && ch
!= '\t')
1721 _cupsLangPuts(stdout
,
1722 _(" WARN File contains a mix of CR, LF, and "
1723 "CR LF line endings."));
1725 if (eol
== EOL_CRLF
)
1726 _cupsLangPuts(stdout
,
1727 _(" WARN Non-Windows PPD files should use lines "
1728 "ending with only LF, not CR LF."));
1735 * 'check_constraints()' - Check UIConstraints in the PPD file.
1738 static int /* O - Errors found */
1739 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1740 int errors
, /* I - Errors found */
1741 int verbose
, /* I - Verbosity level */
1742 int warn
) /* I - Warnings only? */
1744 int i
; /* Looping var */
1745 const char *prefix
; /* WARN/FAIL prefix */
1746 ppd_const_t
*c
; /* Current UIConstraints data */
1747 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1748 const char *vptr
; /* Pointer into constraint value */
1749 char option
[PPD_MAX_NAME
],
1750 /* Option name/MainKeyword */
1751 choice
[PPD_MAX_NAME
],
1752 /* Choice/OptionKeyword */
1753 *ptr
; /* Pointer into option or choice */
1754 int num_options
; /* Number of options */
1755 cups_option_t
*options
; /* Options */
1756 ppd_option_t
*o
; /* PPD option */
1759 prefix
= warn
? " WARN " : "**FAIL**";
1763 * See what kind of constraint data we have in the PPD...
1766 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1769 * Check new-style cupsUIConstraints data...
1773 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1775 if (!constattr
->value
)
1777 if (!warn
&& !errors
&& !verbose
)
1778 _cupsLangPuts(stdout
, _(" FAIL"));
1780 _cupsLangPrintf(stdout
,
1781 _(" %s Empty cupsUIConstraints %s"),
1782 prefix
, constattr
->spec
);
1790 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1792 i
++, vptr
= strchr(vptr
+ 1, '*'));
1796 if (!warn
&& !errors
&& !verbose
)
1797 _cupsLangPuts(stdout
, _(" FAIL"));
1799 _cupsLangPrintf(stdout
,
1800 _(" %s Bad cupsUIConstraints %s: \"%s\""),
1801 prefix
, constattr
->spec
, constattr
->value
);
1809 cupsArraySave(ppd
->sorted_attrs
);
1811 if (constattr
->spec
[0] &&
1812 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1814 if (!warn
&& !errors
&& !verbose
)
1815 _cupsLangPuts(stdout
, _(" FAIL"));
1817 _cupsLangPrintf(stdout
,
1818 _(" %s Missing cupsUIResolver %s"),
1819 prefix
, constattr
->spec
);
1825 cupsArrayRestore(ppd
->sorted_attrs
);
1830 for (vptr
= strchr(constattr
->value
, '*');
1832 vptr
= strchr(vptr
, '*'))
1835 * Extract "*Option Choice" or just "*Option"...
1838 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1839 if (ptr
< (option
+ sizeof(option
) - 1))
1844 while (isspace(*vptr
& 255))
1851 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1852 if (ptr
< (choice
+ sizeof(choice
) - 1))
1858 if (!_cups_strncasecmp(option
, "Custom", 6) && !_cups_strcasecmp(choice
, "True"))
1860 _cups_strcpy(option
, option
+ 6);
1861 strlcpy(choice
, "Custom", sizeof(choice
));
1864 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1866 if (!warn
&& !errors
&& !verbose
)
1867 _cupsLangPuts(stdout
, _(" FAIL"));
1869 _cupsLangPrintf(stdout
,
1870 _(" %s Missing option %s in "
1871 "cupsUIConstraints %s: \"%s\""),
1872 prefix
, option
, constattr
->spec
, constattr
->value
);
1880 if (choice
[0] && !ppdFindChoice(o
, choice
))
1882 if (!warn
&& !errors
&& !verbose
)
1883 _cupsLangPuts(stdout
, _(" FAIL"));
1885 _cupsLangPrintf(stdout
,
1886 _(" %s Missing choice *%s %s in "
1887 "cupsUIConstraints %s: \"%s\""),
1888 prefix
, option
, choice
, constattr
->spec
,
1898 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1901 for (i
= 0; i
< o
->num_choices
; i
++)
1902 if (_cups_strcasecmp(o
->choices
[i
].choice
, "None") &&
1903 _cups_strcasecmp(o
->choices
[i
].choice
, "Off") &&
1904 _cups_strcasecmp(o
->choices
[i
].choice
, "False"))
1906 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
1907 num_options
, &options
);
1914 * Resolvers must list at least two options...
1917 if (num_options
< 2)
1919 if (!warn
&& !errors
&& !verbose
)
1920 _cupsLangPuts(stdout
, _(" FAIL"));
1922 _cupsLangPrintf(stdout
,
1923 _(" %s cupsUIResolver %s does not list at least "
1924 "two different options."),
1925 prefix
, constattr
->spec
);
1932 * Test the resolver...
1935 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
1937 if (!warn
&& !errors
&& !verbose
)
1938 _cupsLangPuts(stdout
, _(" FAIL"));
1940 _cupsLangPrintf(stdout
,
1941 _(" %s cupsUIResolver %s causes a loop."),
1942 prefix
, constattr
->spec
);
1948 cupsFreeOptions(num_options
, options
);
1954 * Check old-style [Non]UIConstraints data...
1957 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1959 if (!_cups_strncasecmp(c
->option1
, "Custom", 6) &&
1960 !_cups_strcasecmp(c
->choice1
, "True"))
1962 strlcpy(option
, c
->option1
+ 6, sizeof(option
));
1963 strlcpy(choice
, "Custom", sizeof(choice
));
1967 strlcpy(option
, c
->option1
, sizeof(option
));
1968 strlcpy(choice
, c
->choice1
, sizeof(choice
));
1971 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1973 if (!warn
&& !errors
&& !verbose
)
1974 _cupsLangPuts(stdout
, _(" FAIL"));
1976 _cupsLangPrintf(stdout
,
1977 _(" %s Missing option %s in "
1978 "UIConstraints \"*%s %s *%s %s\"."),
1980 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1985 else if (choice
[0] && !ppdFindChoice(o
, choice
))
1987 if (!warn
&& !errors
&& !verbose
)
1988 _cupsLangPuts(stdout
, _(" FAIL"));
1990 _cupsLangPrintf(stdout
,
1991 _(" %s Missing choice *%s %s in "
1992 "UIConstraints \"*%s %s *%s %s\"."),
1993 prefix
, c
->option1
, c
->choice1
,
1994 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2000 if (!_cups_strncasecmp(c
->option2
, "Custom", 6) &&
2001 !_cups_strcasecmp(c
->choice2
, "True"))
2003 strlcpy(option
, c
->option2
+ 6, sizeof(option
));
2004 strlcpy(choice
, "Custom", sizeof(choice
));
2008 strlcpy(option
, c
->option2
, sizeof(option
));
2009 strlcpy(choice
, c
->choice2
, sizeof(choice
));
2012 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
2014 if (!warn
&& !errors
&& !verbose
)
2015 _cupsLangPuts(stdout
, _(" FAIL"));
2017 _cupsLangPrintf(stdout
,
2018 _(" %s Missing option %s in "
2019 "UIConstraints \"*%s %s *%s %s\"."),
2021 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2026 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2028 if (!warn
&& !errors
&& !verbose
)
2029 _cupsLangPuts(stdout
, _(" FAIL"));
2031 _cupsLangPrintf(stdout
,
2032 _(" %s Missing choice *%s %s in "
2033 "UIConstraints \"*%s %s *%s %s\"."),
2034 prefix
, c
->option2
, c
->choice2
,
2035 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2048 * 'check_case()' - Check that there are no duplicate groups, options,
2049 * or choices that differ only by case.
2052 static int /* O - Errors found */
2053 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2054 int errors
, /* I - Errors found */
2055 int verbose
) /* I - Verbosity level */
2057 int i
, j
; /* Looping vars */
2058 ppd_group_t
*groupa
, /* First group */
2059 *groupb
; /* Second group */
2060 ppd_option_t
*optiona
, /* First option */
2061 *optionb
; /* Second option */
2062 ppd_choice_t
*choicea
, /* First choice */
2063 *choiceb
; /* Second choice */
2067 * Check that the groups do not have any duplicate names...
2070 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2071 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2072 if (!_cups_strcasecmp(groupa
->name
, groupb
->name
))
2074 if (!errors
&& !verbose
)
2075 _cupsLangPuts(stdout
, _(" FAIL"));
2078 _cupsLangPrintf(stdout
,
2079 _(" **FAIL** Group names %s and %s differ only "
2081 groupa
->name
, groupb
->name
);
2087 * Check that the options do not have any duplicate names...
2090 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2092 cupsArraySave(ppd
->options
);
2093 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2094 if (!_cups_strcasecmp(optiona
->keyword
, optionb
->keyword
))
2096 if (!errors
&& !verbose
)
2097 _cupsLangPuts(stdout
, _(" FAIL"));
2100 _cupsLangPrintf(stdout
,
2101 _(" **FAIL** Option names %s and %s differ only "
2103 optiona
->keyword
, optionb
->keyword
);
2107 cupsArrayRestore(ppd
->options
);
2110 * Then the choices...
2113 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2116 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2117 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2119 if (!errors
&& !verbose
)
2120 _cupsLangPuts(stdout
, _(" FAIL"));
2123 _cupsLangPrintf(stdout
,
2124 _(" **FAIL** Multiple occurrences of "
2125 "option %s choice name %s."),
2126 optiona
->keyword
, choicea
->choice
);
2134 else if (!_cups_strcasecmp(choicea
->choice
, choiceb
->choice
))
2136 if (!errors
&& !verbose
)
2137 _cupsLangPuts(stdout
, _(" FAIL"));
2140 _cupsLangPrintf(stdout
,
2141 _(" **FAIL** Option %s choice names %s and "
2142 "%s differ only by case."),
2143 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2150 * Return the number of errors found...
2158 * 'check_defaults()' - Check default option keywords in the PPD file.
2161 static int /* O - Errors found */
2162 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2163 int errors
, /* I - Errors found */
2164 int verbose
, /* I - Verbosity level */
2165 int warn
) /* I - Warnings only? */
2167 int j
, k
; /* Looping vars */
2168 ppd_attr_t
*attr
; /* PPD attribute */
2169 ppd_option_t
*option
; /* Standard UI option */
2170 const char *prefix
; /* WARN/FAIL prefix */
2173 prefix
= warn
? " WARN " : "**FAIL**";
2175 ppdMarkDefaults(ppd
);
2176 if (ppdConflicts(ppd
))
2178 if (!warn
&& !errors
&& !verbose
)
2179 _cupsLangPuts(stdout
, _(" FAIL"));
2182 _cupsLangPrintf(stdout
,
2183 _(" %s Default choices conflicting."), prefix
);
2185 show_conflicts(ppd
, prefix
);
2191 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2193 attr
= ppd
->attrs
[j
];
2195 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2196 !strcmp(attr
->name
, "DefaultFont") ||
2197 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2198 !strcmp(attr
->name
, "DefaultImageableArea") ||
2199 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2200 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2201 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2202 !strcmp(attr
->name
, "DefaultResolution") ||
2203 !strcmp(attr
->name
, "DefaultTransfer"))
2206 if (!strncmp(attr
->name
, "Default", 7))
2208 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2209 strcmp(attr
->value
, "Unknown"))
2212 * Check that the default option value matches a choice...
2215 for (k
= 0; k
< option
->num_choices
; k
++)
2216 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2219 if (k
>= option
->num_choices
)
2221 if (!warn
&& !errors
&& !verbose
)
2222 _cupsLangPuts(stdout
, _(" FAIL"));
2225 _cupsLangPrintf(stdout
,
2226 _(" %s %s %s does not exist."),
2227 prefix
, attr
->name
, attr
->value
);
2241 * 'check_duplex()' - Check duplex keywords in the PPD file.
2244 static int /* O - Errors found */
2245 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2246 int errors
, /* I - Error found */
2247 int verbose
, /* I - Verbosity level */
2248 int warn
) /* I - Warnings only? */
2250 int i
; /* Looping var */
2251 ppd_option_t
*option
; /* PPD option */
2252 ppd_choice_t
*choice
; /* Current choice */
2253 const char *prefix
; /* Message prefix */
2256 prefix
= warn
? " WARN " : "**FAIL**";
2259 * Check for a duplex option, and for standard values...
2262 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2264 if (!ppdFindChoice(option
, "None"))
2268 if (!warn
&& !errors
&& !verbose
)
2269 _cupsLangPuts(stdout
, _(" FAIL"));
2271 _cupsLangPrintf(stdout
,
2272 _(" %s REQUIRED %s does not define "
2274 " REF: Page 122, section 5.17"),
2275 prefix
, option
->keyword
);
2282 for (i
= option
->num_choices
, choice
= option
->choices
;
2285 if (strcmp(choice
->choice
, "None") &&
2286 strcmp(choice
->choice
, "DuplexNoTumble") &&
2287 strcmp(choice
->choice
, "DuplexTumble") &&
2288 strcmp(choice
->choice
, "SimplexTumble"))
2292 if (!warn
&& !errors
&& !verbose
)
2293 _cupsLangPuts(stdout
, _(" FAIL"));
2295 _cupsLangPrintf(stdout
,
2296 _(" %s Bad %s choice %s.\n"
2297 " REF: Page 122, section 5.17"),
2298 prefix
, option
->keyword
, choice
->choice
);
2311 * 'check_filters()' - Check filters in the PPD file.
2314 static int /* O - Errors found */
2315 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2316 const char *root
, /* I - Root directory */
2317 int errors
, /* I - Errors found */
2318 int verbose
, /* I - Verbosity level */
2319 int warn
) /* I - Warnings only? */
2321 ppd_attr_t
*attr
; /* PPD attribute */
2322 const char *ptr
; /* Pointer into string */
2323 char super
[16], /* Super-type for filter */
2324 type
[256], /* Type for filter */
2325 dstsuper
[16], /* Destination super-type for filter */
2326 dsttype
[256], /* Destination type for filter */
2327 program
[1024], /* Program/filter name */
2328 pathprog
[1024]; /* Complete path to program/filter */
2329 int cost
; /* Cost of filter */
2330 const char *prefix
; /* WARN/FAIL prefix */
2331 struct stat fileinfo
; /* File information */
2334 prefix
= warn
? " WARN " : "**FAIL**";
2340 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
2342 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
2344 if (strcmp(attr
->name
, "cupsFilter"))
2346 if (!warn
&& !errors
&& !verbose
)
2347 _cupsLangPuts(stdout
, _(" FAIL"));
2350 _cupsLangPrintf(stdout
,
2351 _(" %s Bad spelling of %s - should be %s."),
2352 prefix
, attr
->name
, "cupsFilter");
2359 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2360 &cost
, program
) != 4)
2362 if (!warn
&& !errors
&& !verbose
)
2363 _cupsLangPuts(stdout
, _(" FAIL"));
2366 _cupsLangPrintf(stdout
,
2367 _(" %s Bad cupsFilter value \"%s\"."),
2368 prefix
, attr
->value
);
2376 if (!strncmp(program
, "maxsize(", 8))
2378 char *mptr
; /* Pointer into maxsize(nnnn) program */
2380 strtoll(program
+ 8, &mptr
, 10);
2384 if (!warn
&& !errors
&& !verbose
)
2385 _cupsLangPuts(stdout
, _(" FAIL"));
2388 _cupsLangPrintf(stdout
,
2389 _(" %s Bad cupsFilter value \"%s\"."),
2390 prefix
, attr
->value
);
2399 while (_cups_isspace(*mptr
))
2402 _cups_strcpy(program
, mptr
);
2405 if (strcmp(program
, "-"))
2407 if (program
[0] == '/')
2408 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2411 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2412 ptr
= CUPS_SERVERBIN
;
2414 if (*ptr
== '/' || !*root
)
2415 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2418 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2422 if (stat(pathprog
, &fileinfo
))
2424 if (!warn
&& !errors
&& !verbose
)
2425 _cupsLangPuts(stdout
, _(" FAIL"));
2428 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2429 prefix
, "cupsFilter", pathprog
);
2434 else if (fileinfo
.st_uid
!= 0 ||
2435 (fileinfo
.st_mode
& MODE_WRITE
) ||
2436 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2438 if (!warn
&& !errors
&& !verbose
)
2439 _cupsLangPuts(stdout
, _(" FAIL"));
2442 _cupsLangPrintf(stdout
,
2443 _(" %s Bad permissions on %s file \"%s\"."),
2444 prefix
, "cupsFilter", pathprog
);
2450 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2458 for (attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
);
2460 attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
))
2462 if (strcmp(attr
->name
, "cupsFilter2"))
2464 if (!warn
&& !errors
&& !verbose
)
2465 _cupsLangPuts(stdout
, _(" FAIL"));
2468 _cupsLangPrintf(stdout
,
2469 _(" %s Bad spelling of %s - should be %s."),
2470 prefix
, attr
->name
, "cupsFilter2");
2477 sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
2478 super
, type
, dstsuper
, dsttype
, &cost
, program
) != 6)
2480 if (!warn
&& !errors
&& !verbose
)
2481 _cupsLangPuts(stdout
, _(" FAIL"));
2484 _cupsLangPrintf(stdout
,
2485 _(" %s Bad cupsFilter2 value \"%s\"."),
2486 prefix
, attr
->value
);
2494 if (!strncmp(program
, "maxsize(", 8))
2496 char *mptr
; /* Pointer into maxsize(nnnn) program */
2498 strtoll(program
+ 8, &mptr
, 10);
2502 if (!warn
&& !errors
&& !verbose
)
2503 _cupsLangPuts(stdout
, _(" FAIL"));
2506 _cupsLangPrintf(stdout
,
2507 _(" %s Bad cupsFilter2 value \"%s\"."),
2508 prefix
, attr
->value
);
2517 while (_cups_isspace(*mptr
))
2520 _cups_strcpy(program
, mptr
);
2523 if (strcmp(program
, "-"))
2525 if (strncmp(program
, "maxsize(", 8) &&
2526 (ptr
= strchr(program
+ 8, ')')) != NULL
)
2529 while (_cups_isspace(*ptr
))
2532 _cups_strcpy(program
, ptr
);
2535 if (program
[0] == '/')
2536 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2539 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2540 ptr
= CUPS_SERVERBIN
;
2542 if (*ptr
== '/' || !*root
)
2543 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2546 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2550 if (stat(pathprog
, &fileinfo
))
2552 if (!warn
&& !errors
&& !verbose
)
2553 _cupsLangPuts(stdout
, _(" FAIL"));
2556 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2557 prefix
, "cupsFilter2", pathprog
);
2562 else if (fileinfo
.st_uid
!= 0 ||
2563 (fileinfo
.st_mode
& MODE_WRITE
) ||
2564 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2566 if (!warn
&& !errors
&& !verbose
)
2567 _cupsLangPuts(stdout
, _(" FAIL"));
2570 _cupsLangPrintf(stdout
,
2571 _(" %s Bad permissions on %s file \"%s\"."),
2572 prefix
, "cupsFilter2", pathprog
);
2578 errors
= valid_path("cupsFilter2", pathprog
, errors
, verbose
, warn
);
2586 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2588 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2590 if (strcmp(attr
->name
, "cupsPreFilter"))
2592 if (!warn
&& !errors
&& !verbose
)
2593 _cupsLangPuts(stdout
, _(" FAIL"));
2596 _cupsLangPrintf(stdout
,
2597 _(" %s Bad spelling of %s - should be %s."),
2598 prefix
, attr
->name
, "cupsPreFilter");
2605 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2606 &cost
, program
) != 4)
2608 if (!warn
&& !errors
&& !verbose
)
2609 _cupsLangPuts(stdout
, _(" FAIL"));
2612 _cupsLangPrintf(stdout
,
2613 _(" %s Bad cupsPreFilter value \"%s\"."),
2614 prefix
, attr
->value
? attr
->value
: "");
2619 else if (strcmp(program
, "-"))
2621 if (program
[0] == '/')
2622 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2625 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2626 ptr
= CUPS_SERVERBIN
;
2628 if (*ptr
== '/' || !*root
)
2629 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2632 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2636 if (stat(pathprog
, &fileinfo
))
2638 if (!warn
&& !errors
&& !verbose
)
2639 _cupsLangPuts(stdout
, _(" FAIL"));
2642 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2643 prefix
, "cupsPreFilter", pathprog
);
2648 else if (fileinfo
.st_uid
!= 0 ||
2649 (fileinfo
.st_mode
& MODE_WRITE
) ||
2650 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2652 if (!warn
&& !errors
&& !verbose
)
2653 _cupsLangPuts(stdout
, _(" FAIL"));
2656 _cupsLangPrintf(stdout
,
2657 _(" %s Bad permissions on %s file \"%s\"."),
2658 prefix
, "cupsPreFilter", pathprog
);
2664 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2673 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2675 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2677 if (strcmp(attr
->name
, "APDialogExtension"))
2679 if (!warn
&& !errors
&& !verbose
)
2680 _cupsLangPuts(stdout
, _(" FAIL"));
2683 _cupsLangPrintf(stdout
,
2684 _(" %s Bad spelling of %s - should be %s."),
2685 prefix
, attr
->name
, "APDialogExtension");
2691 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2692 attr
->value
? attr
->value
: "(null)");
2694 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2696 if (!warn
&& !errors
&& !verbose
)
2697 _cupsLangPuts(stdout
, _(" FAIL"));
2700 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2701 prefix
, "APDialogExtension", pathprog
);
2706 else if (fileinfo
.st_uid
!= 0 ||
2707 (fileinfo
.st_mode
& MODE_WRITE
) ||
2708 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2710 if (!warn
&& !errors
&& !verbose
)
2711 _cupsLangPuts(stdout
, _(" FAIL"));
2714 _cupsLangPrintf(stdout
,
2715 _(" %s Bad permissions on %s file \"%s\"."),
2716 prefix
, "APDialogExtension", pathprog
);
2722 errors
= valid_path("APDialogExtension", pathprog
, errors
, verbose
,
2730 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2732 if (strcmp(attr
->name
, "APPrinterIconPath"))
2734 if (!warn
&& !errors
&& !verbose
)
2735 _cupsLangPuts(stdout
, _(" FAIL"));
2738 _cupsLangPrintf(stdout
,
2739 _(" %s Bad spelling of %s - should be %s."),
2740 prefix
, attr
->name
, "APPrinterIconPath");
2746 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2747 attr
->value
? attr
->value
: "(null)");
2749 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2751 if (!warn
&& !errors
&& !verbose
)
2752 _cupsLangPuts(stdout
, _(" FAIL"));
2755 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2756 prefix
, "APPrinterIconPath", pathprog
);
2761 else if (fileinfo
.st_uid
!= 0 ||
2762 (fileinfo
.st_mode
& MODE_WRITE
) ||
2763 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2765 if (!warn
&& !errors
&& !verbose
)
2766 _cupsLangPuts(stdout
, _(" FAIL"));
2769 _cupsLangPrintf(stdout
,
2770 _(" %s Bad permissions on %s file \"%s\"."),
2771 prefix
, "APPrinterIconPath", pathprog
);
2777 errors
= valid_path("APPrinterIconPath", pathprog
, errors
, verbose
,
2782 * APPrinterLowInkTool
2785 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2787 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2789 if (!warn
&& !errors
&& !verbose
)
2790 _cupsLangPuts(stdout
, _(" FAIL"));
2793 _cupsLangPrintf(stdout
,
2794 _(" %s Bad spelling of %s - should be %s."),
2795 prefix
, attr
->name
, "APPrinterLowInkTool");
2801 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2802 attr
->value
? attr
->value
: "(null)");
2804 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2806 if (!warn
&& !errors
&& !verbose
)
2807 _cupsLangPuts(stdout
, _(" FAIL"));
2810 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2811 prefix
, "APPrinterLowInkTool", pathprog
);
2816 else if (fileinfo
.st_uid
!= 0 ||
2817 (fileinfo
.st_mode
& MODE_WRITE
) ||
2818 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2820 if (!warn
&& !errors
&& !verbose
)
2821 _cupsLangPuts(stdout
, _(" FAIL"));
2824 _cupsLangPrintf(stdout
,
2825 _(" %s Bad permissions on %s file \"%s\"."),
2826 prefix
, "APPrinterLowInkTool", pathprog
);
2832 errors
= valid_path("APPrinterLowInkTool", pathprog
, errors
, verbose
,
2837 * APPrinterUtilityPath
2840 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2842 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2844 if (!warn
&& !errors
&& !verbose
)
2845 _cupsLangPuts(stdout
, _(" FAIL"));
2848 _cupsLangPrintf(stdout
,
2849 _(" %s Bad spelling of %s - should be %s."),
2850 prefix
, attr
->name
, "APPrinterUtilityPath");
2856 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2857 attr
->value
? attr
->value
: "(null)");
2859 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2861 if (!warn
&& !errors
&& !verbose
)
2862 _cupsLangPuts(stdout
, _(" FAIL"));
2865 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2866 prefix
, "APPrinterUtilityPath", pathprog
);
2871 else if (fileinfo
.st_uid
!= 0 ||
2872 (fileinfo
.st_mode
& MODE_WRITE
) ||
2873 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2875 if (!warn
&& !errors
&& !verbose
)
2876 _cupsLangPuts(stdout
, _(" FAIL"));
2879 _cupsLangPrintf(stdout
,
2880 _(" %s Bad permissions on %s file \"%s\"."),
2881 prefix
, "APPrinterUtilityPath", pathprog
);
2887 errors
= valid_path("APPrinterUtilityPath", pathprog
, errors
, verbose
,
2892 * APScanAppBundleID and APScanAppPath
2895 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2897 if (strcmp(attr
->name
, "APScanAppPath"))
2899 if (!warn
&& !errors
&& !verbose
)
2900 _cupsLangPuts(stdout
, _(" FAIL"));
2903 _cupsLangPrintf(stdout
,
2904 _(" %s Bad spelling of %s - should be %s."),
2905 prefix
, attr
->name
, "APScanAppPath");
2911 if (!attr
->value
|| stat(attr
->value
, &fileinfo
))
2913 if (!warn
&& !errors
&& !verbose
)
2914 _cupsLangPuts(stdout
, _(" FAIL"));
2917 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2918 prefix
, "APScanAppPath",
2919 attr
->value
? attr
->value
: "<NULL>");
2924 else if (fileinfo
.st_uid
!= 0 ||
2925 (fileinfo
.st_mode
& MODE_WRITE
) ||
2926 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2928 if (!warn
&& !errors
&& !verbose
)
2929 _cupsLangPuts(stdout
, _(" FAIL"));
2932 _cupsLangPrintf(stdout
,
2933 _(" %s Bad permissions on %s file \"%s\"."),
2934 prefix
, "APScanAppPath", attr
->value
);
2940 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2943 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2945 if (!warn
&& !errors
&& !verbose
)
2946 _cupsLangPuts(stdout
, _(" FAIL"));
2949 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2950 "APScanAppPath and APScanAppBundleID."),
2957 #endif /* __APPLE__ */
2964 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2967 static int /* O - Errors found */
2968 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2969 const char *root
, /* I - Root directory */
2970 int errors
, /* I - Errors found */
2971 int verbose
, /* I - Verbosity level */
2972 int warn
) /* I - Warnings only? */
2974 int i
; /* Looping var */
2975 ppd_attr_t
*attr
; /* PPD attribute */
2976 const char *ptr
; /* Pointer into string */
2977 const char *prefix
; /* WARN/FAIL prefix */
2978 char filename
[1024]; /* Profile filename */
2979 struct stat fileinfo
; /* File information */
2980 int num_profiles
= 0; /* Number of profiles */
2981 unsigned hash
, /* Current hash value */
2982 hashes
[1000]; /* Hash values of profile names */
2983 const char *specs
[1000]; /* Specifiers for profiles */
2986 prefix
= warn
? " WARN " : "**FAIL**";
2988 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
2990 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
2993 * Check for valid selector...
2996 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
2999 if (!attr
->value
|| i
< 2)
3001 if (!warn
&& !errors
&& !verbose
)
3002 _cupsLangPuts(stdout
, _(" FAIL"));
3005 _cupsLangPrintf(stdout
,
3006 _(" %s Bad cupsICCProfile %s."),
3007 prefix
, attr
->spec
);
3016 * Check for valid profile filename...
3019 if (attr
->value
[0] == '/')
3020 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
3023 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
3026 if (*ptr
== '/' || !*root
)
3027 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
3030 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
3034 if (stat(filename
, &fileinfo
))
3036 if (!warn
&& !errors
&& !verbose
)
3037 _cupsLangPuts(stdout
, _(" FAIL"));
3040 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
3041 prefix
, "cupsICCProfile", filename
);
3046 else if (fileinfo
.st_uid
!= 0 ||
3047 (fileinfo
.st_mode
& MODE_WRITE
) ||
3048 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
3050 if (!warn
&& !errors
&& !verbose
)
3051 _cupsLangPuts(stdout
, _(" FAIL"));
3054 _cupsLangPrintf(stdout
,
3055 _(" %s Bad permissions on %s file \"%s\"."),
3056 prefix
, "cupsICCProfile", filename
);
3062 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
3065 * Check for hash collisions...
3068 hash
= _ppdHashName(attr
->spec
);
3070 if (num_profiles
> 0)
3072 for (i
= 0; i
< num_profiles
; i
++)
3073 if (hashes
[i
] == hash
)
3076 if (i
< num_profiles
)
3078 if (!warn
&& !errors
&& !verbose
)
3079 _cupsLangPuts(stdout
, _(" FAIL"));
3082 _cupsLangPrintf(stdout
,
3083 _(" %s cupsICCProfile %s hash value "
3084 "collides with %s."), prefix
, attr
->spec
,
3093 * Remember up to 1000 profiles...
3096 if (num_profiles
< 1000)
3098 hashes
[num_profiles
] = hash
;
3099 specs
[num_profiles
] = attr
->spec
;
3109 * 'check_sizes()' - Check media sizes in the PPD file.
3112 static int /* O - Errors found */
3113 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
3114 int errors
, /* I - Errors found */
3115 int verbose
, /* I - Verbosity level */
3116 int warn
) /* I - Warnings only? */
3118 int i
; /* Looping var */
3119 ppd_size_t
*size
; /* Current size */
3120 int width
, /* Custom width */
3121 length
; /* Custom length */
3122 const char *prefix
; /* WARN/FAIL prefix */
3123 ppd_option_t
*page_size
, /* PageSize option */
3124 *page_region
; /* PageRegion option */
3125 pwg_media_t
*pwg_media
; /* PWG media */
3126 char buf
[PPD_MAX_NAME
]; /* PapeSize name that is supposed to be */
3127 const char *ptr
; /* Pointer into string */
3128 int width_2540ths
, /* PageSize width in 2540ths */
3129 length_2540ths
; /* PageSize length in 2540ths */
3130 int is_ok
; /* Flag for PageSize name verification */
3131 double width_tmp
, /* Width after rounded up */
3132 length_tmp
, /* Length after rounded up */
3133 width_inch
, /* Width in inches */
3134 length_inch
, /* Length in inches */
3135 width_mm
, /* Width in millimeters */
3136 length_mm
; /* Length in millimeters */
3139 prefix
= warn
? " WARN " : "**FAIL**";
3141 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
3143 if (!warn
&& !errors
&& !verbose
)
3144 _cupsLangPuts(stdout
, _(" FAIL"));
3147 _cupsLangPrintf(stdout
,
3148 _(" %s Missing REQUIRED PageSize option.\n"
3149 " REF: Page 99, section 5.14."),
3156 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
3158 if (!warn
&& !errors
&& !verbose
)
3159 _cupsLangPuts(stdout
, _(" FAIL"));
3162 _cupsLangPrintf(stdout
,
3163 _(" %s Missing REQUIRED PageRegion option.\n"
3164 " REF: Page 100, section 5.14."),
3171 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
3174 * Check that the size name is standard...
3177 if (!strcmp(size
->name
, "Custom"))
3180 * Skip custom page size...
3186 if (warn
!= 2 && size
->name
[0] == 'w' &&
3187 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
3190 * Validate device-specific size wNNNhNNN should have proper width and
3194 if (fabs(width
- size
->width
) >= 1.0 ||
3195 fabs(length
- size
->length
) >= 1.0)
3197 if (!warn
&& !errors
&& !verbose
)
3198 _cupsLangPuts(stdout
, _(" FAIL"));
3201 _cupsLangPrintf(stdout
,
3202 _(" %s Size \"%s\" has unexpected dimensions "
3204 prefix
, size
->name
, size
->width
, size
->length
);
3212 * Verify that the size is defined for both PageSize and PageRegion...
3215 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
3217 if (!warn
&& !errors
&& !verbose
)
3218 _cupsLangPuts(stdout
, _(" FAIL"));
3221 _cupsLangPrintf(stdout
,
3222 _(" %s Size \"%s\" defined for %s but not for "
3224 prefix
, size
->name
, "PageRegion", "PageSize");
3229 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3231 if (!warn
&& !errors
&& !verbose
)
3232 _cupsLangPuts(stdout
, _(" FAIL"));
3235 _cupsLangPrintf(stdout
,
3236 _(" %s Size \"%s\" defined for %s but not for "
3238 prefix
, size
->name
, "PageSize", "PageRegion");
3245 * Verify that the size name is Adobe standard name if it's a standard size
3246 * and the dimentional name if it's not a standard size. Suffix should be
3247 * .Fullbleed, etc., or numeric, e.g., Letter, Letter.Fullbleed,
3248 * Letter.Transverse, Letter1, Letter2, 4x8, 55x91mm, 55x91mm.Fullbleed, etc.
3254 width_2540ths
= (size
->length
> size
->width
) ?
3255 PWG_FROM_POINTS(size
->width
) :
3256 PWG_FROM_POINTS(size
->length
);
3257 length_2540ths
= (size
->length
> size
->width
) ?
3258 PWG_FROM_POINTS(size
->length
) :
3259 PWG_FROM_POINTS(size
->width
);
3260 pwg_media
= pwgMediaForSize(width_2540ths
, length_2540ths
);
3263 (abs(pwg_media
->width
- width_2540ths
) > 34 ||
3264 abs(pwg_media
->length
- length_2540ths
) > 34))
3265 pwg_media
= NULL
; /* Only flag matches within a point */
3267 if (pwg_media
&& pwg_media
->ppd
&&
3268 (pwg_media
->ppd
[0] < 'a' || pwg_media
->ppd
[0] > 'z'))
3270 size_t ppdlen
= strlen(pwg_media
->ppd
);
3271 /* Length of standard PPD name */
3273 strlcpy(buf
, pwg_media
->ppd
, sizeof(buf
));
3275 if (strcmp(size
->name
, buf
) && size
->width
> size
->length
)
3277 if (!strcmp(pwg_media
->ppd
, "DoublePostcardRotated"))
3278 strlcpy(buf
, "DoublePostcard", sizeof(buf
));
3279 else if (strstr(size
->name
, ".Transverse"))
3280 snprintf(buf
, sizeof(buf
), "%s.Transverse", pwg_media
->ppd
);
3282 snprintf(buf
, sizeof(buf
), "%sRotated", pwg_media
->ppd
);
3284 ppdlen
= strlen(buf
);
3287 if (size
->left
== 0 && size
->bottom
== 0 &&
3288 size
->right
== size
->width
&& size
->top
== size
->length
)
3290 strlcat(buf
, ".Fullbleed", sizeof(buf
) - strlen(buf
));
3291 if (_cups_strcasecmp(size
->name
, buf
))
3294 * Allow an additional qualifier such as ".WithTab"...
3297 size_t buflen
= strlen(buf
);/* Length of full bleed name */
3299 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3300 size
->name
[buflen
] != '.')
3304 else if (!strncmp(size
->name
, pwg_media
->ppd
, ppdlen
))
3307 * Check for a proper qualifier (number, "Small", or .something)...
3310 ptr
= size
->name
+ ppdlen
;
3312 if (isdigit(*ptr
& 255))
3314 for (ptr
++; *ptr
; ptr
++)
3316 if (!isdigit(*ptr
& 255))
3323 else if (*ptr
!= '.' && *ptr
&& strcmp(ptr
, "Small"))
3329 * Check for EnvSizeName as well...
3332 if (strncmp(pwg_media
->ppd
, "Env", 3) &&
3333 !strncmp(size
->name
, "Env", 3))
3334 snprintf(buf
, sizeof(buf
), "Env%s", pwg_media
->ppd
);
3336 if (strcmp(size
->name
, buf
))
3341 _cupsLangPrintf(stdout
,
3342 _(" %s Size \"%s\" should be the Adobe "
3343 "standard name \"%s\"."),
3344 prefix
, size
->name
, buf
);
3348 width_tmp
= (fabs(size
->width
- ceil(size
->width
)) < 0.1) ?
3349 ceil(size
->width
) : size
->width
;
3350 length_tmp
= (fabs(size
->length
- ceil(size
->length
)) < 0.1) ?
3351 ceil(size
->length
) : size
->length
;
3353 if (fmod(width_tmp
, 9.0) == 0.0 && fmod(length_tmp
, 9.0) == 0.0)
3355 width_inch
= width_tmp
/ 72.0;
3356 length_inch
= length_tmp
/ 72.0;
3358 snprintf(buf
, sizeof(buf
), "%gx%g", width_inch
, length_inch
);
3362 width_mm
= size
->width
/ 72.0 * 25.4;
3363 length_mm
= size
->length
/ 72.0 * 25.4;
3365 snprintf(buf
, sizeof(buf
), "%.0fx%.0fmm", width_mm
, length_mm
);
3368 if (size
->left
== 0 && size
->bottom
== 0 &&
3369 size
->right
== size
->width
&& size
->top
== size
->length
)
3370 strlcat(buf
, ".Fullbleed", sizeof(buf
));
3371 else if (size
->width
> size
->length
)
3372 strlcat(buf
, ".Transverse", sizeof(buf
));
3374 if (_cups_strcasecmp(size
->name
, buf
))
3376 size_t buflen
= strlen(buf
);
3377 /* Length of proposed name */
3379 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3380 (strcmp(size
->name
+ buflen
, "in") &&
3381 size
->name
[buflen
] != '.'))
3383 char altbuf
[PPD_MAX_NAME
];
3384 /* Alternate "wNNNhNNN" name */
3385 size_t altlen
; /* Length of alternate name */
3387 snprintf(altbuf
, sizeof(altbuf
), "w%.0fh%.0f", size
->width
,
3389 altlen
= strlen(altbuf
);
3390 if (_cups_strncasecmp(size
->name
, altbuf
, altlen
) ||
3391 (size
->name
[altlen
] && size
->name
[altlen
] != '.'))
3392 _cupsLangPrintf(stdout
,
3393 _(" %s Size \"%s\" should be \"%s\"."),
3394 prefix
, size
->name
, buf
);
3406 * 'check_translations()' - Check translations in the PPD file.
3409 static int /* O - Errors found */
3410 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3411 int errors
, /* I - Errors found */
3412 int verbose
, /* I - Verbosity level */
3413 int warn
) /* I - Warnings only? */
3415 int j
; /* Looping var */
3416 ppd_attr_t
*attr
; /* PPD attribute */
3417 cups_array_t
*languages
; /* Array of languages */
3418 int langlen
; /* Length of language */
3419 char *language
, /* Current language */
3420 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3421 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3422 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3423 cllkeyword
[PPD_MAX_NAME
];
3424 /* Custom option keyword (base) */
3425 ppd_option_t
*option
; /* Standard UI option */
3426 ppd_coption_t
*coption
; /* Custom option */
3427 ppd_cparam_t
*cparam
; /* Custom parameter */
3428 char ll
[3]; /* Base language */
3429 const char *prefix
; /* WARN/FAIL prefix */
3430 const char *text
; /* Pointer into UI text */
3433 prefix
= warn
? " WARN " : "**FAIL**";
3435 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3438 * This file contains localizations, check them...
3441 for (language
= (char *)cupsArrayFirst(languages
);
3443 language
= (char *)cupsArrayNext(languages
))
3445 langlen
= (int)strlen(language
);
3446 if (langlen
!= 2 && langlen
!= 5)
3448 if (!warn
&& !errors
&& !verbose
)
3449 _cupsLangPuts(stdout
, _(" FAIL"));
3452 _cupsLangPrintf(stdout
,
3453 _(" %s Bad language \"%s\"."),
3462 if (!strcmp(language
, "en"))
3465 strlcpy(ll
, language
, sizeof(ll
));
3468 * Loop through all options and choices...
3471 for (option
= ppdFirstOption(ppd
);
3473 option
= ppdNextOption(ppd
))
3475 if (!strcmp(option
->keyword
, "PageRegion"))
3478 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3479 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3481 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3482 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3484 if (!warn
&& !errors
&& !verbose
)
3485 _cupsLangPuts(stdout
, _(" FAIL"));
3488 _cupsLangPrintf(stdout
,
3489 _(" %s Missing \"%s\" translation "
3490 "string for option %s."),
3491 prefix
, language
, option
->keyword
);
3496 else if (!valid_utf8(attr
->text
))
3498 if (!warn
&& !errors
&& !verbose
)
3499 _cupsLangPuts(stdout
, _(" FAIL"));
3502 _cupsLangPrintf(stdout
,
3503 _(" %s Bad UTF-8 \"%s\" translation "
3504 "string for option %s."),
3505 prefix
, language
, option
->keyword
);
3511 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3513 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3516 for (j
= 0; j
< option
->num_choices
; j
++)
3519 * First see if this choice is a number; if so, don't require
3523 for (text
= option
->choices
[j
].text
; *text
; text
++)
3524 if (!strchr("0123456789-+.", *text
))
3531 * Check custom choices differently...
3534 if (!_cups_strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3535 (coption
= ppdFindCustomOption(ppd
,
3536 option
->keyword
)) != NULL
)
3538 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3539 language
, option
->keyword
);
3541 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3542 !valid_utf8(attr
->text
))
3544 if (!warn
&& !errors
&& !verbose
)
3545 _cupsLangPuts(stdout
, _(" FAIL"));
3548 _cupsLangPrintf(stdout
,
3549 _(" %s Bad UTF-8 \"%s\" "
3550 "translation string for option %s, "
3553 ckeyword
+ 1 + strlen(language
),
3560 if (_cups_strcasecmp(option
->keyword
, "PageSize"))
3562 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3564 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3566 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3567 language
, option
->keyword
);
3568 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3569 ll
, option
->keyword
);
3571 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3572 cparam
->name
)) == NULL
&&
3573 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3574 cparam
->name
)) == NULL
)
3576 if (!warn
&& !errors
&& !verbose
)
3577 _cupsLangPuts(stdout
, _(" FAIL"));
3580 _cupsLangPrintf(stdout
,
3581 _(" %s Missing \"%s\" "
3582 "translation string for option %s, "
3585 ckeyword
+ 1 + strlen(language
),
3591 else if (!valid_utf8(attr
->text
))
3593 if (!warn
&& !errors
&& !verbose
)
3594 _cupsLangPuts(stdout
, _(" FAIL"));
3597 _cupsLangPrintf(stdout
,
3598 _(" %s Bad UTF-8 \"%s\" "
3599 "translation string for option %s, "
3602 ckeyword
+ 1 + strlen(language
),
3611 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3612 option
->choices
[j
].choice
)) == NULL
&&
3613 (attr
= ppdFindAttr(ppd
, llkeyword
,
3614 option
->choices
[j
].choice
)) == NULL
)
3616 if (!warn
&& !errors
&& !verbose
)
3617 _cupsLangPuts(stdout
, _(" FAIL"));
3620 _cupsLangPrintf(stdout
,
3621 _(" %s Missing \"%s\" "
3622 "translation string for option %s, "
3624 prefix
, language
, option
->keyword
,
3625 option
->choices
[j
].choice
);
3630 else if (!valid_utf8(attr
->text
))
3632 if (!warn
&& !errors
&& !verbose
)
3633 _cupsLangPuts(stdout
, _(" FAIL"));
3636 _cupsLangPrintf(stdout
,
3637 _(" %s Bad UTF-8 \"%s\" "
3638 "translation string for option %s, "
3640 prefix
, language
, option
->keyword
,
3641 option
->choices
[j
].choice
);
3651 * Verify that we have the base language for each localized one...
3654 for (language
= (char *)cupsArrayFirst(languages
);
3656 language
= (char *)cupsArrayNext(languages
))
3660 * Lookup the base language...
3663 cupsArraySave(languages
);
3665 strlcpy(ll
, language
, sizeof(ll
));
3667 if (!cupsArrayFind(languages
, ll
) &&
3668 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3670 if (!warn
&& !errors
&& !verbose
)
3671 _cupsLangPuts(stdout
, _(" FAIL"));
3674 _cupsLangPrintf(stdout
,
3675 _(" %s No base translation \"%s\" "
3676 "is included in file."), prefix
, ll
);
3682 cupsArrayRestore(languages
);
3686 * Free memory used for the languages...
3689 _ppdFreeLanguages(languages
);
3697 * 'show_conflicts()' - Show option conflicts in a PPD file.
3701 show_conflicts(ppd_file_t
*ppd
, /* I - PPD to check */
3702 const char *prefix
) /* I - Prefix string */
3704 int i
, j
; /* Looping variables */
3705 ppd_const_t
*c
; /* Current constraint */
3706 ppd_option_t
*o1
, *o2
; /* Options */
3707 ppd_choice_t
*c1
, *c2
; /* Choices */
3711 * Loop through all of the UI constraints and report any options
3715 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3718 * Grab pointers to the first option...
3721 o1
= ppdFindOption(ppd
, c
->option1
);
3725 else if (c
->choice1
[0] != '\0')
3728 * This constraint maps to a specific choice.
3731 c1
= ppdFindChoice(o1
, c
->choice1
);
3736 * This constraint applies to any choice for this option.
3739 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3744 !_cups_strcasecmp(c1
->choice
, "None") ||
3745 !_cups_strcasecmp(c1
->choice
, "Off") ||
3746 !_cups_strcasecmp(c1
->choice
, "False"))
3751 * Grab pointers to the second option...
3754 o2
= ppdFindOption(ppd
, c
->option2
);
3758 else if (c
->choice2
[0] != '\0')
3761 * This constraint maps to a specific choice.
3764 c2
= ppdFindChoice(o2
, c
->choice2
);
3769 * This constraint applies to any choice for this option.
3772 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3777 !_cups_strcasecmp(c2
->choice
, "None") ||
3778 !_cups_strcasecmp(c2
->choice
, "Off") ||
3779 !_cups_strcasecmp(c2
->choice
, "False"))
3784 * If both options are marked then there is a conflict...
3787 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3788 _cupsLangPrintf(stdout
,
3789 _(" %s \"%s %s\" conflicts with \"%s %s\"\n"
3790 " (constraint=\"%s %s %s %s\")."),
3791 prefix
, o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3792 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3798 * 'test_raster()' - Test PostScript commands for raster printers.
3801 static int /* O - 1 on success, 0 on failure */
3802 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3803 int verbose
) /* I - Verbosity */
3805 cups_page_header2_t header
; /* Page header */
3808 ppdMarkDefaults(ppd
);
3809 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3812 _cupsLangPuts(stdout
, _(" FAIL"));
3815 _cupsLangPrintf(stdout
,
3816 _(" **FAIL** Default option code cannot be "
3817 "interpreted: %s"), cupsRasterErrorString());
3823 * Try a test of custom page size code, if available...
3826 if (!ppdPageSize(ppd
, "Custom.612x792"))
3829 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3831 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3834 _cupsLangPuts(stdout
, _(" FAIL"));
3837 _cupsLangPrintf(stdout
,
3838 _(" **FAIL** Default option code cannot be "
3839 "interpreted: %s"), cupsRasterErrorString());
3849 * 'usage()' - Show program usage.
3855 _cupsLangPuts(stdout
, _("Usage: cupstestppd [options] filename1.ppd[.gz] "
3856 "[... filenameN.ppd[.gz]]"));
3857 _cupsLangPuts(stdout
, _(" program | cupstestppd [options] -"));
3858 _cupsLangPuts(stdout
, "");
3859 _cupsLangPuts(stdout
, _("Options:"));
3860 _cupsLangPuts(stdout
, "");
3861 _cupsLangPuts(stdout
, _(" -I {filename,filters,none,profiles}"));
3862 _cupsLangPuts(stdout
, _(" Ignore specific warnings."));
3863 _cupsLangPuts(stdout
, _(" -R root-directory Set alternate root."));
3864 _cupsLangPuts(stdout
, _(" -W {all,none,constraints,defaults,duplex,"
3865 "filters,profiles,sizes,translations}"));
3866 _cupsLangPuts(stdout
, _(" Issue warnings instead of "
3868 _cupsLangPuts(stdout
, _(" -q Run silently."));
3869 _cupsLangPuts(stdout
, _(" -r Use 'relaxed' open mode."));
3870 _cupsLangPuts(stdout
, _(" -v Be verbose."));
3871 _cupsLangPuts(stdout
, _(" -vv Be very verbose."));
3878 * 'valid_path()' - Check whether a path has the correct capitalization.
3881 static int /* O - Errors found */
3882 valid_path(const char *keyword
, /* I - Keyword using path */
3883 const char *path
, /* I - Path to check */
3884 int errors
, /* I - Errors found */
3885 int verbose
, /* I - Verbosity level */
3886 int warn
) /* I - Warnings only? */
3888 cups_dir_t
*dir
; /* Current directory */
3889 cups_dentry_t
*dentry
; /* Current directory entry */
3890 char temp
[1024], /* Temporary path */
3891 *ptr
; /* Pointer into temporary path */
3892 const char *prefix
; /* WARN/FAIL prefix */
3895 prefix
= warn
? " WARN " : "**FAIL**";
3898 * Loop over the components of the path, checking that the entry exists with
3899 * the same capitalization...
3902 strlcpy(temp
, path
, sizeof(temp
));
3904 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3907 * Chop off the trailing component so temp == dirname and ptr == basename.
3913 * Try opening the directory containing the base name...
3917 dir
= cupsDirOpen(temp
);
3919 dir
= cupsDirOpen("/");
3925 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3927 if (!strcmp(dentry
->filename
, ptr
))
3935 * Display an error if the filename doesn't exist with the same
3941 if (!warn
&& !errors
&& !verbose
)
3942 _cupsLangPuts(stdout
, _(" FAIL"));
3945 _cupsLangPrintf(stdout
,
3946 _(" %s %s file \"%s\" has the wrong "
3947 "capitalization."), prefix
, keyword
, path
);
3961 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3964 static int /* O - 1 if valid, 0 if not */
3965 valid_utf8(const char *s
) /* I - String to check */
3972 * Check for valid UTF-8 sequence...
3975 if ((*s
& 0xc0) == 0x80)
3976 return (0); /* Illegal suffix byte */
3977 else if ((*s
& 0xe0) == 0xc0)
3980 * 2-byte sequence...
3985 if ((*s
& 0xc0) != 0x80)
3986 return (0); /* Missing suffix byte */
3988 else if ((*s
& 0xf0) == 0xe0)
3991 * 3-byte sequence...
3996 if ((*s
& 0xc0) != 0x80)
3997 return (0); /* Missing suffix byte */
4001 if ((*s
& 0xc0) != 0x80)
4002 return (0); /* Missing suffix byte */
4004 else if ((*s
& 0xf8) == 0xf0)
4007 * 4-byte sequence...
4012 if ((*s
& 0xc0) != 0x80)
4013 return (0); /* Missing suffix byte */
4017 if ((*s
& 0xc0) != 0x80)
4018 return (0); /* Missing suffix byte */
4022 if ((*s
& 0xc0) != 0x80)
4023 return (0); /* Missing suffix byte */
4026 return (0); /* Bad sequence */