4 * PPD test program for CUPS.
6 * Copyright 2007-2013 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/cups-private.h>
46 #include <cups/ppd-private.h>
47 #include <cups/raster.h>
55 * Error warning overrides...
65 WARN_TRANSLATIONS
= 16,
101 * File permissions...
104 #define MODE_WRITE 0022 /* Group/other write */
105 #define MODE_MASK 0555 /* Owner/group/other read+exec/search */
106 #define MODE_DATAFILE 0444 /* Owner/group/other read */
107 #define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
108 #define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
115 static void check_basics(const char *filename
);
116 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
118 static int check_case(ppd_file_t
*ppd
, int errors
, int verbose
);
119 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
121 static int check_duplex(ppd_file_t
*ppd
, int errors
, int verbose
,
123 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
124 int verbose
, int warn
);
125 static int check_profiles(ppd_file_t
*ppd
, const char *root
, int errors
,
126 int verbose
, int warn
);
127 static int check_sizes(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
128 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,
130 static void show_conflicts(ppd_file_t
*ppd
, const char *prefix
);
131 static int test_raster(ppd_file_t
*ppd
, int verbose
);
132 static void usage(void) __attribute__((noreturn
));
133 static int valid_path(const char *keyword
, const char *path
, int errors
,
134 int verbose
, int warn
);
135 static int valid_utf8(const char *s
);
139 * 'main()' - Main entry for test program.
142 int /* O - Exit status */
143 main(int argc
, /* I - Number of command-line args */
144 char *argv
[]) /* I - Command-line arguments */
146 int i
, j
, k
, m
, n
; /* Looping vars */
147 int len
; /* Length of option name */
148 char *opt
; /* Option character */
149 const char *ptr
; /* Pointer into string */
150 cups_file_t
*fp
; /* PPD file */
151 int files
; /* Number of files */
152 int verbose
; /* Want verbose output? */
153 int warn
; /* Which errors to just warn about */
154 int ignore
; /* Which errors to ignore */
155 int status
; /* Exit status */
156 int errors
; /* Number of conformance errors */
157 int ppdversion
; /* PPD spec version in PPD file */
158 ppd_status_t error
; /* Status of ppdOpen*() */
159 int line
; /* Line number for error */
160 char *root
; /* Root directory */
161 int xdpi
, /* X resolution */
162 ydpi
; /* Y resolution */
163 ppd_file_t
*ppd
; /* PPD file record */
164 ppd_attr_t
*attr
; /* PPD attribute */
165 ppd_size_t
*size
; /* Size record */
166 ppd_group_t
*group
; /* UI group */
167 ppd_option_t
*option
; /* Standard UI option */
168 ppd_group_t
*group2
; /* UI group */
169 ppd_option_t
*option2
; /* Standard UI option */
170 ppd_choice_t
*choice
; /* Standard UI option choice */
171 struct lconv
*loc
; /* Locale data */
172 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
173 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
174 "JCL", "PAGE", "PROLOG" };
177 _cupsSetLocale(argv
);
181 * Display PPD files for each file listed on the command-line...
184 ppdSetConformance(PPD_CONFORM_STRICT
);
194 for (i
= 1; i
< argc
; i
++)
195 if (argv
[i
][0] == '-' && argv
[i
][1])
197 for (opt
= argv
[i
] + 1; *opt
; opt
++)
200 case 'I' : /* Ignore errors */
206 if (!strcmp(argv
[i
], "none"))
208 else if (!strcmp(argv
[i
], "filename"))
209 ignore
|= WARN_FILENAME
;
210 else if (!strcmp(argv
[i
], "filters"))
211 ignore
|= WARN_FILTERS
;
212 else if (!strcmp(argv
[i
], "profiles"))
213 ignore
|= WARN_PROFILES
;
214 else if (!strcmp(argv
[i
], "all"))
215 ignore
= WARN_FILTERS
| WARN_PROFILES
;
220 case 'R' : /* Alternate root directory */
229 case 'W' : /* Turn errors into warnings */
235 if (!strcmp(argv
[i
], "none"))
237 else if (!strcmp(argv
[i
], "constraints"))
238 warn
|= WARN_CONSTRAINTS
;
239 else if (!strcmp(argv
[i
], "defaults"))
240 warn
|= WARN_DEFAULTS
;
241 else if (!strcmp(argv
[i
], "duplex"))
243 else if (!strcmp(argv
[i
], "filters"))
244 warn
|= WARN_FILTERS
;
245 else if (!strcmp(argv
[i
], "profiles"))
246 warn
|= WARN_PROFILES
;
247 else if (!strcmp(argv
[i
], "sizes"))
249 else if (!strcmp(argv
[i
], "translations"))
250 warn
|= WARN_TRANSLATIONS
;
251 else if (!strcmp(argv
[i
], "all"))
257 case 'q' : /* Quiet mode */
260 _cupsLangPuts(stderr
,
261 _("cupstestppd: The -q option is incompatible "
262 "with the -v option."));
269 case 'r' : /* Relaxed mode */
270 ppdSetConformance(PPD_CONFORM_RELAXED
);
273 case 'v' : /* Verbose mode */
276 _cupsLangPuts(stderr
,
277 _("cupstestppd: The -v option is incompatible "
278 "with the -q option."));
293 * Open the PPD file...
296 if (files
&& verbose
>= 0)
301 if (argv
[i
][0] == '-')
307 ppd
= _ppdOpen(cupsFileStdin(), _PPD_LOCALIZATION_ALL
);
310 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
315 * Read from a file...
319 printf("%s:", argv
[i
]);
321 if ((fp
= cupsFileOpen(argv
[i
], "r")) != NULL
)
323 ppd
= _ppdOpen(fp
, _PPD_LOCALIZATION_ALL
);
328 status
= ERROR_FILE_OPEN
;
332 _cupsLangPuts(stdout
, _(" FAIL"));
333 _cupsLangPrintf(stdout
,
334 _(" **FAIL** Unable to open PPD file - %s on "
335 "line %d."), strerror(errno
), 0);
343 error
= ppdLastError(&line
);
345 if (error
<= PPD_ALLOC_ERROR
)
347 status
= ERROR_FILE_OPEN
;
351 _cupsLangPuts(stdout
, _(" FAIL"));
352 _cupsLangPrintf(stdout
,
353 _(" **FAIL** Unable to open PPD file - %s on "
354 "line %d."), strerror(errno
), 0);
359 status
= ERROR_PPD_FORMAT
;
363 _cupsLangPuts(stdout
, _(" FAIL"));
364 _cupsLangPrintf(stdout
,
365 _(" **FAIL** Unable to open PPD file - "
367 ppdErrorString(error
), line
);
371 case PPD_MISSING_PPDADOBE4
:
372 _cupsLangPuts(stdout
,
373 _(" REF: Page 42, section "
376 case PPD_MISSING_VALUE
:
377 _cupsLangPuts(stdout
,
378 _(" REF: Page 20, section "
381 case PPD_BAD_OPEN_GROUP
:
382 case PPD_NESTED_OPEN_GROUP
:
383 _cupsLangPuts(stdout
,
384 _(" REF: Pages 45-46, section "
387 case PPD_BAD_OPEN_UI
:
388 case PPD_NESTED_OPEN_UI
:
389 _cupsLangPuts(stdout
,
390 _(" REF: Pages 42-45, section "
393 case PPD_BAD_ORDER_DEPENDENCY
:
394 _cupsLangPuts(stdout
,
395 _(" REF: Pages 48-49, section "
398 case PPD_BAD_UI_CONSTRAINTS
:
399 _cupsLangPuts(stdout
,
400 _(" REF: Pages 52-54, section "
403 case PPD_MISSING_ASTERISK
:
404 _cupsLangPuts(stdout
,
405 _(" REF: Page 15, section "
408 case PPD_LINE_TOO_LONG
:
409 _cupsLangPuts(stdout
,
410 _(" REF: Page 15, section "
413 case PPD_ILLEGAL_CHARACTER
:
414 _cupsLangPuts(stdout
,
415 _(" REF: Page 15, section "
418 case PPD_ILLEGAL_MAIN_KEYWORD
:
419 _cupsLangPuts(stdout
,
420 _(" REF: Pages 16-17, section "
423 case PPD_ILLEGAL_OPTION_KEYWORD
:
424 _cupsLangPuts(stdout
,
425 _(" REF: Page 19, section "
428 case PPD_ILLEGAL_TRANSLATION
:
429 _cupsLangPuts(stdout
,
430 _(" REF: Page 27, section "
437 check_basics(argv
[i
]);
445 * Show the header and then perform basic conformance tests (limited
446 * only by what the CUPS PPD functions actually load...)
453 _cupsLangPuts(stdout
,
454 _("\n DETAILED CONFORMANCE TEST RESULTS"));
456 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
458 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
460 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) != NULL
)
464 if (strstr(attr
->value
, "application/vnd.cups-raster"))
466 if (!test_raster(ppd
, verbose
))
471 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
475 for (j
= 0; j
< ppd
->num_filters
; j
++)
476 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
478 if (!test_raster(ppd
, verbose
))
485 * Look for default keywords with no matching option...
488 if (!(warn
& WARN_DEFAULTS
))
489 errors
= check_defaults(ppd
, errors
, verbose
, 0);
491 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
495 if (!errors
&& !verbose
)
496 _cupsLangPuts(stdout
, _(" FAIL"));
498 _cupsLangPuts(stdout
,
499 _(" **FAIL** REQUIRED DefaultImageableArea\n"
500 " REF: Page 102, section 5.15."));
505 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
506 strcmp(attr
->value
, "Unknown"))
510 if (!errors
&& !verbose
)
511 _cupsLangPuts(stdout
, _(" FAIL"));
513 _cupsLangPrintf(stdout
,
514 _(" **FAIL** Bad DefaultImageableArea %s\n"
515 " REF: Page 102, section 5.15."),
524 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea"));
527 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
531 if (!errors
&& !verbose
)
532 _cupsLangPuts(stdout
, _(" FAIL"));
534 _cupsLangPuts(stdout
,
535 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
536 " REF: Page 103, section 5.15."));
541 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
542 strcmp(attr
->value
, "Unknown"))
546 if (!errors
&& !verbose
)
547 _cupsLangPuts(stdout
, _(" FAIL"));
549 _cupsLangPrintf(stdout
,
550 _(" **FAIL** Bad DefaultPaperDimension %s\n"
551 " REF: Page 103, section 5.15."),
557 else if (verbose
> 0)
558 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension"));
560 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
561 for (k
= 0, option
= group
->options
;
562 k
< group
->num_options
;
566 * Verify that we have a default choice...
569 if (option
->defchoice
[0])
571 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
572 strcmp(option
->defchoice
, "Unknown"))
576 if (!errors
&& !verbose
)
577 _cupsLangPuts(stdout
, _(" FAIL"));
579 _cupsLangPrintf(stdout
,
580 _(" **FAIL** Bad Default%s %s\n"
581 " REF: Page 40, section 4.5."),
582 option
->keyword
, option
->defchoice
);
587 else if (verbose
> 0)
588 _cupsLangPrintf(stdout
,
589 _(" PASS Default%s"),
596 if (!errors
&& !verbose
)
597 _cupsLangPuts(stdout
, _(" FAIL"));
599 _cupsLangPrintf(stdout
,
600 _(" **FAIL** REQUIRED Default%s\n"
601 " REF: Page 40, section 4.5."),
609 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
611 for (ptr
= attr
->value
; *ptr
; ptr
++)
612 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
619 if (!errors
&& !verbose
)
620 _cupsLangPuts(stdout
, _(" FAIL"));
622 _cupsLangPrintf(stdout
,
623 _(" **FAIL** Bad FileVersion \"%s\"\n"
624 " REF: Page 56, section 5.3."),
630 else if (verbose
> 0)
631 _cupsLangPuts(stdout
, _(" PASS FileVersion"));
637 if (!errors
&& !verbose
)
638 _cupsLangPuts(stdout
, _(" FAIL"));
640 _cupsLangPuts(stdout
,
641 _(" **FAIL** REQUIRED FileVersion\n"
642 " REF: Page 56, section 5.3."));
648 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
651 if (*ptr
== '4' && ptr
[1] == '.')
654 for (ptr
+= 2; *ptr
; ptr
++)
655 if (!isdigit(*ptr
& 255))
663 if (!errors
&& !verbose
)
664 _cupsLangPuts(stdout
, _(" FAIL"));
666 _cupsLangPrintf(stdout
,
667 _(" **FAIL** Bad FormatVersion \"%s\"\n"
668 " REF: Page 56, section 5.3."),
674 else if (verbose
> 0)
675 _cupsLangPuts(stdout
, _(" PASS FormatVersion"));
681 if (!errors
&& !verbose
)
682 _cupsLangPuts(stdout
, _(" FAIL"));
684 _cupsLangPuts(stdout
,
685 _(" **FAIL** REQUIRED FormatVersion\n"
686 " REF: Page 56, section 5.3."));
692 if (ppd
->lang_encoding
!= NULL
)
695 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding"));
697 else if (ppdversion
> 40)
701 if (!errors
&& !verbose
)
702 _cupsLangPuts(stdout
, _(" FAIL"));
704 _cupsLangPuts(stdout
,
705 _(" **FAIL** REQUIRED LanguageEncoding\n"
706 " REF: Pages 56-57, section 5.3."));
712 if (ppd
->lang_version
!= NULL
)
715 _cupsLangPuts(stdout
, _(" PASS LanguageVersion"));
721 if (!errors
&& !verbose
)
722 _cupsLangPuts(stdout
, _(" FAIL"));
724 _cupsLangPuts(stdout
,
725 _(" **FAIL** REQUIRED LanguageVersion\n"
726 " REF: Pages 57-58, section 5.3."));
732 if (ppd
->manufacturer
!= NULL
)
734 if (!_cups_strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
735 !_cups_strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
739 if (!errors
&& !verbose
)
740 _cupsLangPuts(stdout
, _(" FAIL"));
742 _cupsLangPrintf(stdout
,
743 _(" **FAIL** Bad Manufacturer (should be "
745 " REF: Page 211, table D.1."),
751 else if (!_cups_strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
752 !_cups_strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
756 if (!errors
&& !verbose
)
757 _cupsLangPuts(stdout
, _(" FAIL"));
759 _cupsLangPrintf(stdout
,
760 _(" **FAIL** Bad Manufacturer (should be "
762 " REF: Page 211, table D.1."),
768 else if (verbose
> 0)
769 _cupsLangPuts(stdout
, _(" PASS Manufacturer"));
771 else if (ppdversion
>= 43)
775 if (!errors
&& !verbose
)
776 _cupsLangPuts(stdout
, _(" FAIL"));
778 _cupsLangPuts(stdout
,
779 _(" **FAIL** REQUIRED Manufacturer\n"
780 " REF: Pages 58-59, section 5.3."));
786 if (ppd
->modelname
!= NULL
)
788 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
789 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
796 if (!errors
&& !verbose
)
797 _cupsLangPuts(stdout
, _(" FAIL"));
799 _cupsLangPrintf(stdout
,
800 _(" **FAIL** Bad ModelName - \"%c\" not "
801 "allowed in string.\n"
802 " REF: Pages 59-60, section 5.3."),
808 else if (verbose
> 0)
809 _cupsLangPuts(stdout
, _(" PASS ModelName"));
815 if (!errors
&& !verbose
)
816 _cupsLangPuts(stdout
, _(" FAIL"));
818 _cupsLangPuts(stdout
,
819 _(" **FAIL** REQUIRED ModelName\n"
820 " REF: Pages 59-60, section 5.3."));
826 if (ppd
->nickname
!= NULL
)
829 _cupsLangPuts(stdout
, _(" PASS NickName"));
835 if (!errors
&& !verbose
)
836 _cupsLangPuts(stdout
, _(" FAIL"));
838 _cupsLangPuts(stdout
,
839 _(" **FAIL** REQUIRED NickName\n"
840 " REF: Page 60, section 5.3."));
846 if (ppdFindOption(ppd
, "PageSize") != NULL
)
849 _cupsLangPuts(stdout
, _(" PASS PageSize"));
855 if (!errors
&& !verbose
)
856 _cupsLangPuts(stdout
, _(" FAIL"));
858 _cupsLangPuts(stdout
,
859 _(" **FAIL** REQUIRED PageSize\n"
860 " REF: Pages 99-100, section 5.14."));
866 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
869 _cupsLangPuts(stdout
, _(" PASS PageRegion"));
875 if (!errors
&& !verbose
)
876 _cupsLangPuts(stdout
, _(" FAIL"));
878 _cupsLangPuts(stdout
,
879 _(" **FAIL** REQUIRED PageRegion\n"
880 " REF: Page 100, section 5.14."));
886 if (ppd
->pcfilename
!= NULL
)
889 _cupsLangPuts(stdout
, _(" PASS PCFileName"));
891 else if (!(ignore
& WARN_FILENAME
))
895 if (!errors
&& !verbose
)
896 _cupsLangPuts(stdout
, _(" FAIL"));
898 _cupsLangPuts(stdout
,
899 _(" **FAIL** REQUIRED PCFileName\n"
900 " REF: Pages 61-62, section 5.3."));
906 if (ppd
->product
!= NULL
)
908 if (ppd
->product
[0] != '(' ||
909 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
913 if (!errors
&& !verbose
)
914 _cupsLangPuts(stdout
, _(" FAIL"));
916 _cupsLangPuts(stdout
,
917 _(" **FAIL** Bad Product - not \"(string)\".\n"
918 " REF: Page 62, section 5.3."));
923 else if (verbose
> 0)
924 _cupsLangPuts(stdout
, _(" PASS Product"));
930 if (!errors
&& !verbose
)
931 _cupsLangPuts(stdout
, _(" FAIL"));
933 _cupsLangPuts(stdout
,
934 _(" **FAIL** REQUIRED Product\n"
935 " REF: Page 62, section 5.3."));
941 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
944 char junkstr
[255]; /* Temp string */
945 int junkint
; /* Temp integer */
948 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
952 if (!errors
&& !verbose
)
953 _cupsLangPuts(stdout
, _(" FAIL"));
955 _cupsLangPuts(stdout
,
956 _(" **FAIL** Bad PSVersion - not \"(string) "
958 " REF: Pages 62-64, section 5.3."));
963 else if (verbose
> 0)
964 _cupsLangPuts(stdout
, _(" PASS PSVersion"));
970 if (!errors
&& !verbose
)
971 _cupsLangPuts(stdout
, _(" FAIL"));
973 _cupsLangPuts(stdout
,
974 _(" **FAIL** REQUIRED PSVersion\n"
975 " REF: Pages 62-64, section 5.3."));
981 if (ppd
->shortnickname
!= NULL
)
983 if (strlen(ppd
->shortnickname
) > 31)
987 if (!errors
&& !verbose
)
988 _cupsLangPuts(stdout
, _(" FAIL"));
990 _cupsLangPuts(stdout
,
991 _(" **FAIL** Bad ShortNickName - longer "
993 " REF: Pages 64-65, section 5.3."));
998 else if (verbose
> 0)
999 _cupsLangPuts(stdout
, _(" PASS ShortNickName"));
1001 else if (ppdversion
>= 43)
1005 if (!errors
&& !verbose
)
1006 _cupsLangPuts(stdout
, _(" FAIL"));
1008 _cupsLangPuts(stdout
,
1009 _(" **FAIL** REQUIRED ShortNickName\n"
1010 " REF: Page 64-65, section 5.3."));
1016 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
1017 strstr(ppd
->patches
, "*End"))
1021 if (!errors
&& !verbose
)
1022 _cupsLangPuts(stdout
, _(" FAIL"));
1024 _cupsLangPuts(stdout
,
1025 _(" **FAIL** Bad JobPatchFile attribute in file\n"
1026 " REF: Page 24, section 3.4."));
1033 * Check for page sizes without the corresponding ImageableArea or
1034 * PaperDimension values...
1037 if (ppd
->num_sizes
== 0)
1041 if (!errors
&& !verbose
)
1042 _cupsLangPuts(stdout
, _(" FAIL"));
1044 _cupsLangPuts(stdout
,
1045 _(" **FAIL** REQUIRED PageSize\n"
1046 " REF: Page 41, section 5.\n"
1047 " REF: Page 99, section 5.14."));
1054 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1057 * Don't check custom size...
1060 if (!strcmp(size
->name
, "Custom"))
1064 * Check for ImageableArea...
1067 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1068 size
->right
== 0.0 && size
->top
== 0.0)
1072 if (!errors
&& !verbose
)
1073 _cupsLangPuts(stdout
, _(" FAIL"));
1075 _cupsLangPrintf(stdout
,
1076 _(" **FAIL** REQUIRED ImageableArea for "
1078 " REF: Page 41, section 5.\n"
1079 " REF: Page 102, section 5.15."),
1087 * Check for PaperDimension...
1090 if (size
->width
<= 0.0 && size
->length
<= 0.0)
1094 if (!errors
&& !verbose
)
1095 _cupsLangPuts(stdout
, _(" FAIL"));
1097 _cupsLangPrintf(stdout
,
1098 _(" **FAIL** REQUIRED PaperDimension "
1100 " REF: Page 41, section 5.\n"
1101 " REF: Page 103, section 5.15."),
1111 * Check for valid Resolution, JCLResolution, or SetResolution values...
1114 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1115 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1116 option
= ppdFindOption(ppd
, "SetResolution");
1120 for (j
= option
->num_choices
, choice
= option
->choices
;
1125 * Verify that all resolution options are of the form NNNdpi
1129 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1130 if (ptr
> choice
->choice
&& xdpi
> 0)
1133 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1140 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1145 if (!errors
&& !verbose
)
1146 _cupsLangPuts(stdout
, _(" FAIL"));
1148 _cupsLangPrintf(stdout
,
1149 _(" **FAIL** Bad option %s choice %s\n"
1150 " REF: Page 84, section 5.9"),
1151 option
->keyword
, choice
->choice
);
1159 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1160 strcmp(attr
->name
, "1284DeviceID"))
1164 if (!errors
&& !verbose
)
1165 _cupsLangPuts(stdout
, _(" FAIL"));
1167 _cupsLangPrintf(stdout
,
1168 _(" **FAIL** %s must be 1284DeviceID\n"
1169 " REF: Page 72, section 5.5"),
1176 errors
= check_case(ppd
, errors
, verbose
);
1178 if (!(warn
& WARN_CONSTRAINTS
))
1179 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1181 if (!(warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1182 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1184 if (!(warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1185 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1187 if (!(warn
& WARN_SIZES
))
1188 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1190 if (!(warn
& WARN_TRANSLATIONS
))
1191 errors
= check_translations(ppd
, errors
, verbose
, 0);
1193 if (!(warn
& WARN_DUPLEX
))
1194 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1196 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1200 * This file contains localizations, check for conformance of the
1201 * base translation...
1204 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1206 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1208 if (!errors
&& !verbose
)
1209 _cupsLangPuts(stdout
, _(" FAIL"));
1212 _cupsLangPrintf(stdout
,
1213 _(" **FAIL** Bad LanguageEncoding %s - "
1214 "must be ISOLatin1."),
1215 attr
->value
? attr
->value
: "(null)");
1220 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1222 if (!errors
&& !verbose
)
1223 _cupsLangPuts(stdout
, _(" FAIL"));
1226 _cupsLangPrintf(stdout
,
1227 _(" **FAIL** Bad LanguageVersion %s - "
1228 "must be English."),
1229 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1235 * Loop through all options and choices...
1238 for (option
= ppdFirstOption(ppd
);
1240 option
= ppdNextOption(ppd
))
1243 * Check for special characters outside A0 to BF, F7, or F8
1244 * that are used for languages other than English.
1247 for (ptr
= option
->text
; *ptr
; ptr
++)
1248 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1249 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1254 if (!errors
&& !verbose
)
1255 _cupsLangPuts(stdout
, _(" FAIL"));
1258 _cupsLangPrintf(stdout
,
1259 _(" **FAIL** Default translation "
1260 "string for option %s contains 8-bit "
1267 for (j
= 0; j
< option
->num_choices
; j
++)
1270 * Check for special characters outside A0 to BF, F7, or F8
1271 * that are used for languages other than English.
1274 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1275 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1276 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1281 if (!errors
&& !verbose
)
1282 _cupsLangPuts(stdout
, _(" FAIL"));
1285 _cupsLangPrintf(stdout
,
1286 _(" **FAIL** Default translation "
1287 "string for option %s choice %s contains "
1288 "8-bit characters."),
1290 option
->choices
[j
].choice
);
1300 * Final pass/fail notification...
1304 status
= ERROR_CONFORMANCE
;
1306 _cupsLangPuts(stdout
, _(" PASS"));
1310 check_basics(argv
[i
]);
1312 if (warn
& WARN_DEFAULTS
)
1313 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1315 if (warn
& WARN_CONSTRAINTS
)
1316 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1318 if ((warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1319 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1321 if ((warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1322 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1324 if (warn
& WARN_SIZES
)
1325 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1327 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1329 if (warn
& WARN_TRANSLATIONS
)
1330 errors
= check_translations(ppd
, errors
, verbose
, 1);
1332 if (warn
& WARN_DUPLEX
)
1333 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1336 * Look for legacy duplex keywords...
1339 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1340 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1341 option
= ppdFindOption(ppd
, "KD03Duplex");
1344 _cupsLangPrintf(stdout
,
1345 _(" WARN Duplex option keyword %s may not "
1346 "work as expected and should be named Duplex.\n"
1347 " REF: Page 122, section 5.17"),
1351 * Look for default keywords with no corresponding option...
1354 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1356 attr
= ppd
->attrs
[j
];
1358 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1359 !strcmp(attr
->name
, "DefaultColorSep") ||
1360 !strcmp(attr
->name
, "DefaultFont") ||
1361 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1362 !strcmp(attr
->name
, "DefaultImageableArea") ||
1363 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1364 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1365 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1366 !strcmp(attr
->name
, "DefaultResolution") ||
1367 !strcmp(attr
->name
, "DefaultScreenProc") ||
1368 !strcmp(attr
->name
, "DefaultTransfer"))
1371 if (!strncmp(attr
->name
, "Default", 7) &&
1372 !ppdFindOption(ppd
, attr
->name
+ 7))
1373 _cupsLangPrintf(stdout
,
1374 _(" WARN %s has no corresponding "
1379 if (ppdversion
< 43)
1381 _cupsLangPrintf(stdout
,
1382 _(" WARN Obsolete PPD version %.1f.\n"
1383 " REF: Page 42, section 5.2."),
1387 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1389 _cupsLangPuts(stdout
,
1390 _(" WARN LanguageEncoding required by PPD "
1392 " REF: Pages 56-57, section 5.3."));
1395 if (!ppd
->manufacturer
&& ppdversion
< 43)
1397 _cupsLangPuts(stdout
,
1398 _(" WARN Manufacturer required by PPD "
1400 " REF: Pages 58-59, section 5.3."));
1404 * Treat a PCFileName attribute longer than 12 characters as
1405 * a warning and not a hard error...
1408 if (!(ignore
& WARN_FILENAME
) && ppd
->pcfilename
)
1410 if (strlen(ppd
->pcfilename
) > 12)
1412 _cupsLangPuts(stdout
,
1413 _(" WARN PCFileName longer than 8.3 in "
1414 "violation of PPD spec.\n"
1415 " REF: Pages 61-62, section "
1419 if (!_cups_strcasecmp(ppd
->pcfilename
, "unused.ppd"))
1420 _cupsLangPuts(stdout
,
1421 _(" WARN PCFileName should contain a "
1422 "unique filename.\n"
1423 " REF: Pages 61-62, section "
1427 if (!ppd
->shortnickname
&& ppdversion
< 43)
1429 _cupsLangPuts(stdout
,
1430 _(" WARN ShortNickName required by PPD "
1432 " REF: Pages 64-65, section 5.3."));
1436 * Check the Protocols line and flag PJL + BCP since TBCP is
1437 * usually used with PJL...
1442 if (strstr(ppd
->protocols
, "PJL") &&
1443 strstr(ppd
->protocols
, "BCP") &&
1444 !strstr(ppd
->protocols
, "TBCP"))
1446 _cupsLangPuts(stdout
,
1447 _(" WARN Protocols contains both PJL "
1448 "and BCP; expected TBCP.\n"
1449 " REF: Pages 78-79, section 5.7."));
1452 if (strstr(ppd
->protocols
, "PJL") &&
1453 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1455 _cupsLangPuts(stdout
,
1456 _(" WARN Protocols contains PJL but JCL "
1457 "attributes are not set.\n"
1458 " REF: Pages 78-79, section 5.7."));
1463 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1464 * which are errors according to the spec but won't cause problems
1465 * with CUPS specifically...
1468 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1469 for (k
= 0, option
= group
->options
;
1470 k
< group
->num_options
;
1473 len
= (int)strlen(option
->keyword
);
1475 for (m
= 0, group2
= ppd
->groups
;
1476 m
< ppd
->num_groups
;
1478 for (n
= 0, option2
= group2
->options
;
1479 n
< group2
->num_options
;
1481 if (option
!= option2
&&
1482 len
< (int)strlen(option2
->keyword
) &&
1483 !strncmp(option
->keyword
, option2
->keyword
, len
))
1485 _cupsLangPrintf(stdout
,
1486 _(" WARN %s shares a common "
1488 " REF: Page 15, section "
1490 option
->keyword
, option2
->keyword
);
1498 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND"), errors
);
1500 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND"));
1504 * Then list the options, if "-v" was provided...
1509 _cupsLangPrintf(stdout
,
1511 " language_level = %d\n"
1512 " color_device = %s\n"
1513 " variable_sizes = %s\n"
1515 ppd
->language_level
,
1516 ppd
->color_device
? "TRUE" : "FALSE",
1517 ppd
->variable_sizes
? "TRUE" : "FALSE",
1520 switch (ppd
->colorspace
)
1523 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK");
1526 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY");
1529 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY");
1532 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB");
1535 _cupsLangPuts(stdout
, " colorspace = <unknown>");
1539 _cupsLangPrintf(stdout
, " num_emulations = %d",
1540 ppd
->num_emulations
);
1541 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1542 _cupsLangPrintf(stdout
, " emulations[%d] = %s",
1543 j
, ppd
->emulations
[j
].name
);
1545 _cupsLangPrintf(stdout
, " lang_encoding = %s",
1546 ppd
->lang_encoding
);
1547 _cupsLangPrintf(stdout
, " lang_version = %s",
1549 _cupsLangPrintf(stdout
, " modelname = %s", ppd
->modelname
);
1550 _cupsLangPrintf(stdout
, " ttrasterizer = %s",
1551 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1552 _cupsLangPrintf(stdout
, " manufacturer = %s",
1554 _cupsLangPrintf(stdout
, " product = %s", ppd
->product
);
1555 _cupsLangPrintf(stdout
, " nickname = %s", ppd
->nickname
);
1556 _cupsLangPrintf(stdout
, " shortnickname = %s",
1557 ppd
->shortnickname
);
1558 _cupsLangPrintf(stdout
, " patches = %d bytes",
1559 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1561 _cupsLangPrintf(stdout
, " num_groups = %d", ppd
->num_groups
);
1562 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1564 _cupsLangPrintf(stdout
, " group[%d] = %s",
1567 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1569 _cupsLangPrintf(stdout
,
1570 " options[%d] = %s (%s) %s %s %.0f "
1572 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1573 sections
[option
->section
], option
->order
,
1574 option
->num_choices
);
1576 if (!strcmp(option
->keyword
, "PageSize") ||
1577 !strcmp(option
->keyword
, "PageRegion"))
1579 for (m
= option
->num_choices
, choice
= option
->choices
;
1583 size
= ppdPageSize(ppd
, choice
->choice
);
1586 _cupsLangPrintf(stdout
,
1587 " %s (%s) = ERROR%s",
1588 choice
->choice
, choice
->text
,
1589 !strcmp(option
->defchoice
, choice
->choice
)
1592 _cupsLangPrintf(stdout
,
1593 " %s (%s) = %.2fx%.2fin "
1594 "(%.1f,%.1f,%.1f,%.1f)%s",
1595 choice
->choice
, choice
->text
,
1596 size
->width
/ 72.0, size
->length
/ 72.0,
1597 size
->left
/ 72.0, size
->bottom
/ 72.0,
1598 size
->right
/ 72.0, size
->top
/ 72.0,
1599 !strcmp(option
->defchoice
, choice
->choice
)
1605 for (m
= option
->num_choices
, choice
= option
->choices
;
1609 _cupsLangPrintf(stdout
, " %s (%s)%s",
1610 choice
->choice
, choice
->text
,
1611 !strcmp(option
->defchoice
, choice
->choice
)
1618 _cupsLangPrintf(stdout
, " num_consts = %d",
1620 for (j
= 0; j
< ppd
->num_consts
; j
++)
1621 _cupsLangPrintf(stdout
,
1622 " consts[%d] = *%s %s *%s %s",
1623 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1624 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1626 _cupsLangPrintf(stdout
, " num_profiles = %d",
1628 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1629 _cupsLangPrintf(stdout
,
1630 " profiles[%d] = %s/%s %.3f %.3f "
1631 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]",
1632 j
, ppd
->profiles
[j
].resolution
,
1633 ppd
->profiles
[j
].media_type
,
1634 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1635 ppd
->profiles
[j
].matrix
[0][0],
1636 ppd
->profiles
[j
].matrix
[0][1],
1637 ppd
->profiles
[j
].matrix
[0][2],
1638 ppd
->profiles
[j
].matrix
[1][0],
1639 ppd
->profiles
[j
].matrix
[1][1],
1640 ppd
->profiles
[j
].matrix
[1][2],
1641 ppd
->profiles
[j
].matrix
[2][0],
1642 ppd
->profiles
[j
].matrix
[2][1],
1643 ppd
->profiles
[j
].matrix
[2][2]);
1645 _cupsLangPrintf(stdout
, " num_fonts = %d", ppd
->num_fonts
);
1646 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1647 _cupsLangPrintf(stdout
, " fonts[%d] = %s",
1650 _cupsLangPrintf(stdout
, " num_attrs = %d", ppd
->num_attrs
);
1651 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1652 _cupsLangPrintf(stdout
,
1653 " attrs[%d] = %s %s%s%s: \"%s\"", j
,
1654 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1655 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1656 ppd
->attrs
[j
]->text
,
1657 ppd
->attrs
[j
]->value
?
1658 ppd
->attrs
[j
]->value
: "(null)");
1672 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1676 check_basics(const char *filename
) /* I - PPD file to check */
1678 cups_file_t
*fp
; /* File pointer */
1679 int ch
; /* Current character */
1680 int col
, /* Current column */
1681 whitespace
; /* Only seen whitespace? */
1682 int eol
; /* Line endings */
1683 int linenum
; /* Line number */
1684 int mixed
; /* Mixed line endings? */
1687 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1696 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1698 if (ch
== '\r' || ch
== '\n')
1702 if (eol
== EOL_NONE
)
1704 else if (eol
!= EOL_LF
)
1707 else if (ch
== '\r')
1709 if (cupsFilePeekChar(fp
) == '\n')
1711 cupsFileGetChar(fp
);
1713 if (eol
== EOL_NONE
)
1715 else if (eol
!= EOL_CRLF
)
1718 else if (eol
== EOL_NONE
)
1720 else if (eol
!= EOL_CR
)
1724 if (col
> 0 && whitespace
)
1725 _cupsLangPrintf(stdout
,
1726 _(" WARN Line %d only contains whitespace."),
1735 if (ch
!= ' ' && ch
!= '\t')
1743 _cupsLangPuts(stdout
,
1744 _(" WARN File contains a mix of CR, LF, and "
1745 "CR LF line endings."));
1747 if (eol
== EOL_CRLF
)
1748 _cupsLangPuts(stdout
,
1749 _(" WARN Non-Windows PPD files should use lines "
1750 "ending with only LF, not CR LF."));
1757 * 'check_constraints()' - Check UIConstraints in the PPD file.
1760 static int /* O - Errors found */
1761 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1762 int errors
, /* I - Errors found */
1763 int verbose
, /* I - Verbosity level */
1764 int warn
) /* I - Warnings only? */
1766 int i
; /* Looping var */
1767 const char *prefix
; /* WARN/FAIL prefix */
1768 ppd_const_t
*c
; /* Current UIConstraints data */
1769 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1770 const char *vptr
; /* Pointer into constraint value */
1771 char option
[PPD_MAX_NAME
],
1772 /* Option name/MainKeyword */
1773 choice
[PPD_MAX_NAME
],
1774 /* Choice/OptionKeyword */
1775 *ptr
; /* Pointer into option or choice */
1776 int num_options
; /* Number of options */
1777 cups_option_t
*options
; /* Options */
1778 ppd_option_t
*o
; /* PPD option */
1781 prefix
= warn
? " WARN " : "**FAIL**";
1785 * See what kind of constraint data we have in the PPD...
1788 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1791 * Check new-style cupsUIConstraints data...
1795 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1797 if (!constattr
->value
)
1799 if (!warn
&& !errors
&& !verbose
)
1800 _cupsLangPuts(stdout
, _(" FAIL"));
1802 _cupsLangPrintf(stdout
,
1803 _(" %s Empty cupsUIConstraints %s"),
1804 prefix
, constattr
->spec
);
1812 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1814 i
++, vptr
= strchr(vptr
+ 1, '*'));
1818 if (!warn
&& !errors
&& !verbose
)
1819 _cupsLangPuts(stdout
, _(" FAIL"));
1821 _cupsLangPrintf(stdout
,
1822 _(" %s Bad cupsUIConstraints %s: \"%s\""),
1823 prefix
, constattr
->spec
, constattr
->value
);
1831 cupsArraySave(ppd
->sorted_attrs
);
1833 if (constattr
->spec
[0] &&
1834 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1836 if (!warn
&& !errors
&& !verbose
)
1837 _cupsLangPuts(stdout
, _(" FAIL"));
1839 _cupsLangPrintf(stdout
,
1840 _(" %s Missing cupsUIResolver %s"),
1841 prefix
, constattr
->spec
);
1847 cupsArrayRestore(ppd
->sorted_attrs
);
1852 for (vptr
= strchr(constattr
->value
, '*');
1854 vptr
= strchr(vptr
, '*'))
1857 * Extract "*Option Choice" or just "*Option"...
1860 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1861 if (ptr
< (option
+ sizeof(option
) - 1))
1866 while (isspace(*vptr
& 255))
1873 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1874 if (ptr
< (choice
+ sizeof(choice
) - 1))
1880 if (!_cups_strncasecmp(option
, "Custom", 6) && !_cups_strcasecmp(choice
, "True"))
1882 _cups_strcpy(option
, option
+ 6);
1883 strlcpy(choice
, "Custom", sizeof(choice
));
1886 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1888 if (!warn
&& !errors
&& !verbose
)
1889 _cupsLangPuts(stdout
, _(" FAIL"));
1891 _cupsLangPrintf(stdout
,
1892 _(" %s Missing option %s in "
1893 "cupsUIConstraints %s: \"%s\""),
1894 prefix
, option
, constattr
->spec
, constattr
->value
);
1902 if (choice
[0] && !ppdFindChoice(o
, choice
))
1904 if (!warn
&& !errors
&& !verbose
)
1905 _cupsLangPuts(stdout
, _(" FAIL"));
1907 _cupsLangPrintf(stdout
,
1908 _(" %s Missing choice *%s %s in "
1909 "cupsUIConstraints %s: \"%s\""),
1910 prefix
, option
, choice
, constattr
->spec
,
1920 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1923 for (i
= 0; i
< o
->num_choices
; i
++)
1924 if (_cups_strcasecmp(o
->choices
[i
].choice
, "None") &&
1925 _cups_strcasecmp(o
->choices
[i
].choice
, "Off") &&
1926 _cups_strcasecmp(o
->choices
[i
].choice
, "False"))
1928 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
1929 num_options
, &options
);
1936 * Resolvers must list at least two options...
1939 if (num_options
< 2)
1941 if (!warn
&& !errors
&& !verbose
)
1942 _cupsLangPuts(stdout
, _(" FAIL"));
1944 _cupsLangPrintf(stdout
,
1945 _(" %s cupsUIResolver %s does not list at least "
1946 "two different options."),
1947 prefix
, constattr
->spec
);
1954 * Test the resolver...
1957 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
1959 if (!warn
&& !errors
&& !verbose
)
1960 _cupsLangPuts(stdout
, _(" FAIL"));
1962 _cupsLangPrintf(stdout
,
1963 _(" %s cupsUIResolver %s causes a loop."),
1964 prefix
, constattr
->spec
);
1970 cupsFreeOptions(num_options
, options
);
1976 * Check old-style [Non]UIConstraints data...
1979 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1981 if (!_cups_strncasecmp(c
->option1
, "Custom", 6) &&
1982 !_cups_strcasecmp(c
->choice1
, "True"))
1984 strlcpy(option
, c
->option1
+ 6, sizeof(option
));
1985 strlcpy(choice
, "Custom", sizeof(choice
));
1989 strlcpy(option
, c
->option1
, sizeof(option
));
1990 strlcpy(choice
, c
->choice1
, sizeof(choice
));
1993 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1995 if (!warn
&& !errors
&& !verbose
)
1996 _cupsLangPuts(stdout
, _(" FAIL"));
1998 _cupsLangPrintf(stdout
,
1999 _(" %s Missing option %s in "
2000 "UIConstraints \"*%s %s *%s %s\"."),
2002 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2007 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2009 if (!warn
&& !errors
&& !verbose
)
2010 _cupsLangPuts(stdout
, _(" FAIL"));
2012 _cupsLangPrintf(stdout
,
2013 _(" %s Missing choice *%s %s in "
2014 "UIConstraints \"*%s %s *%s %s\"."),
2015 prefix
, c
->option1
, c
->choice1
,
2016 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2022 if (!_cups_strncasecmp(c
->option2
, "Custom", 6) &&
2023 !_cups_strcasecmp(c
->choice2
, "True"))
2025 strlcpy(option
, c
->option2
+ 6, sizeof(option
));
2026 strlcpy(choice
, "Custom", sizeof(choice
));
2030 strlcpy(option
, c
->option2
, sizeof(option
));
2031 strlcpy(choice
, c
->choice2
, sizeof(choice
));
2034 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
2036 if (!warn
&& !errors
&& !verbose
)
2037 _cupsLangPuts(stdout
, _(" FAIL"));
2039 _cupsLangPrintf(stdout
,
2040 _(" %s Missing option %s in "
2041 "UIConstraints \"*%s %s *%s %s\"."),
2043 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2048 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2050 if (!warn
&& !errors
&& !verbose
)
2051 _cupsLangPuts(stdout
, _(" FAIL"));
2053 _cupsLangPrintf(stdout
,
2054 _(" %s Missing choice *%s %s in "
2055 "UIConstraints \"*%s %s *%s %s\"."),
2056 prefix
, c
->option2
, c
->choice2
,
2057 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2070 * 'check_case()' - Check that there are no duplicate groups, options,
2071 * or choices that differ only by case.
2074 static int /* O - Errors found */
2075 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2076 int errors
, /* I - Errors found */
2077 int verbose
) /* I - Verbosity level */
2079 int i
, j
; /* Looping vars */
2080 ppd_group_t
*groupa
, /* First group */
2081 *groupb
; /* Second group */
2082 ppd_option_t
*optiona
, /* First option */
2083 *optionb
; /* Second option */
2084 ppd_choice_t
*choicea
, /* First choice */
2085 *choiceb
; /* Second choice */
2089 * Check that the groups do not have any duplicate names...
2092 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2093 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2094 if (!_cups_strcasecmp(groupa
->name
, groupb
->name
))
2096 if (!errors
&& !verbose
)
2097 _cupsLangPuts(stdout
, _(" FAIL"));
2100 _cupsLangPrintf(stdout
,
2101 _(" **FAIL** Group names %s and %s differ only "
2103 groupa
->name
, groupb
->name
);
2109 * Check that the options do not have any duplicate names...
2112 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2114 cupsArraySave(ppd
->options
);
2115 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2116 if (!_cups_strcasecmp(optiona
->keyword
, optionb
->keyword
))
2118 if (!errors
&& !verbose
)
2119 _cupsLangPuts(stdout
, _(" FAIL"));
2122 _cupsLangPrintf(stdout
,
2123 _(" **FAIL** Option names %s and %s differ only "
2125 optiona
->keyword
, optionb
->keyword
);
2129 cupsArrayRestore(ppd
->options
);
2132 * Then the choices...
2135 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2138 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2139 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2141 if (!errors
&& !verbose
)
2142 _cupsLangPuts(stdout
, _(" FAIL"));
2145 _cupsLangPrintf(stdout
,
2146 _(" **FAIL** Multiple occurrences of "
2147 "option %s choice name %s."),
2148 optiona
->keyword
, choicea
->choice
);
2156 else if (!_cups_strcasecmp(choicea
->choice
, choiceb
->choice
))
2158 if (!errors
&& !verbose
)
2159 _cupsLangPuts(stdout
, _(" FAIL"));
2162 _cupsLangPrintf(stdout
,
2163 _(" **FAIL** Option %s choice names %s and "
2164 "%s differ only by case."),
2165 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2172 * Return the number of errors found...
2180 * 'check_defaults()' - Check default option keywords in the PPD file.
2183 static int /* O - Errors found */
2184 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2185 int errors
, /* I - Errors found */
2186 int verbose
, /* I - Verbosity level */
2187 int warn
) /* I - Warnings only? */
2189 int j
, k
; /* Looping vars */
2190 ppd_attr_t
*attr
; /* PPD attribute */
2191 ppd_option_t
*option
; /* Standard UI option */
2192 const char *prefix
; /* WARN/FAIL prefix */
2195 prefix
= warn
? " WARN " : "**FAIL**";
2197 ppdMarkDefaults(ppd
);
2198 if (ppdConflicts(ppd
))
2200 if (!warn
&& !errors
&& !verbose
)
2201 _cupsLangPuts(stdout
, _(" FAIL"));
2204 _cupsLangPrintf(stdout
,
2205 _(" %s Default choices conflicting."), prefix
);
2207 show_conflicts(ppd
, prefix
);
2213 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2215 attr
= ppd
->attrs
[j
];
2217 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2218 !strcmp(attr
->name
, "DefaultFont") ||
2219 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2220 !strcmp(attr
->name
, "DefaultImageableArea") ||
2221 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2222 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2223 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2224 !strcmp(attr
->name
, "DefaultResolution") ||
2225 !strcmp(attr
->name
, "DefaultTransfer"))
2228 if (!strncmp(attr
->name
, "Default", 7))
2230 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2231 strcmp(attr
->value
, "Unknown"))
2234 * Check that the default option value matches a choice...
2237 for (k
= 0; k
< option
->num_choices
; k
++)
2238 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2241 if (k
>= option
->num_choices
)
2243 if (!warn
&& !errors
&& !verbose
)
2244 _cupsLangPuts(stdout
, _(" FAIL"));
2247 _cupsLangPrintf(stdout
,
2248 _(" %s %s %s does not exist."),
2249 prefix
, attr
->name
, attr
->value
);
2263 * 'check_duplex()' - Check duplex keywords in the PPD file.
2266 static int /* O - Errors found */
2267 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2268 int errors
, /* I - Error found */
2269 int verbose
, /* I - Verbosity level */
2270 int warn
) /* I - Warnings only? */
2272 int i
; /* Looping var */
2273 ppd_option_t
*option
; /* PPD option */
2274 ppd_choice_t
*choice
; /* Current choice */
2275 const char *prefix
; /* Message prefix */
2278 prefix
= warn
? " WARN " : "**FAIL**";
2281 * Check for a duplex option, and for standard values...
2284 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2286 if (!ppdFindChoice(option
, "None"))
2290 if (!warn
&& !errors
&& !verbose
)
2291 _cupsLangPuts(stdout
, _(" FAIL"));
2293 _cupsLangPrintf(stdout
,
2294 _(" %s REQUIRED %s does not define "
2296 " REF: Page 122, section 5.17"),
2297 prefix
, option
->keyword
);
2304 for (i
= option
->num_choices
, choice
= option
->choices
;
2307 if (strcmp(choice
->choice
, "None") &&
2308 strcmp(choice
->choice
, "DuplexNoTumble") &&
2309 strcmp(choice
->choice
, "DuplexTumble") &&
2310 strcmp(choice
->choice
, "SimplexTumble"))
2314 if (!warn
&& !errors
&& !verbose
)
2315 _cupsLangPuts(stdout
, _(" FAIL"));
2317 _cupsLangPrintf(stdout
,
2318 _(" %s Bad %s choice %s.\n"
2319 " REF: Page 122, section 5.17"),
2320 prefix
, option
->keyword
, choice
->choice
);
2333 * 'check_filters()' - Check filters in the PPD file.
2336 static int /* O - Errors found */
2337 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2338 const char *root
, /* I - Root directory */
2339 int errors
, /* I - Errors found */
2340 int verbose
, /* I - Verbosity level */
2341 int warn
) /* I - Warnings only? */
2343 ppd_attr_t
*attr
; /* PPD attribute */
2344 const char *ptr
; /* Pointer into string */
2345 char super
[16], /* Super-type for filter */
2346 type
[256], /* Type for filter */
2347 dstsuper
[16], /* Destination super-type for filter */
2348 dsttype
[256], /* Destination type for filter */
2349 program
[1024], /* Program/filter name */
2350 pathprog
[1024]; /* Complete path to program/filter */
2351 int cost
; /* Cost of filter */
2352 const char *prefix
; /* WARN/FAIL prefix */
2353 struct stat fileinfo
; /* File information */
2356 prefix
= warn
? " WARN " : "**FAIL**";
2362 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
2364 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
2366 if (strcmp(attr
->name
, "cupsFilter"))
2368 if (!warn
&& !errors
&& !verbose
)
2369 _cupsLangPuts(stdout
, _(" FAIL"));
2372 _cupsLangPrintf(stdout
,
2373 _(" %s Bad spelling of %s - should be %s."),
2374 prefix
, attr
->name
, "cupsFilter");
2381 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2382 &cost
, program
) != 4)
2384 if (!warn
&& !errors
&& !verbose
)
2385 _cupsLangPuts(stdout
, _(" FAIL"));
2388 _cupsLangPrintf(stdout
,
2389 _(" %s Bad cupsFilter value \"%s\"."),
2390 prefix
, attr
->value
);
2395 else if (strcmp(program
, "-"))
2397 if (program
[0] == '/')
2398 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2401 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2402 ptr
= CUPS_SERVERBIN
;
2404 if (*ptr
== '/' || !*root
)
2405 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2408 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2412 if (stat(pathprog
, &fileinfo
))
2414 if (!warn
&& !errors
&& !verbose
)
2415 _cupsLangPuts(stdout
, _(" FAIL"));
2418 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2419 prefix
, "cupsFilter", pathprog
);
2424 else if (fileinfo
.st_uid
!= 0 ||
2425 (fileinfo
.st_mode
& MODE_WRITE
) ||
2426 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2428 if (!warn
&& !errors
&& !verbose
)
2429 _cupsLangPuts(stdout
, _(" FAIL"));
2432 _cupsLangPrintf(stdout
,
2433 _(" %s Bad permissions on %s file \"%s\"."),
2434 prefix
, "cupsFilter", pathprog
);
2440 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2448 for (attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
);
2450 attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
))
2452 if (strcmp(attr
->name
, "cupsFilter2"))
2454 if (!warn
&& !errors
&& !verbose
)
2455 _cupsLangPuts(stdout
, _(" FAIL"));
2458 _cupsLangPrintf(stdout
,
2459 _(" %s Bad spelling of %s - should be %s."),
2460 prefix
, attr
->name
, "cupsFilter2");
2467 sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
2468 super
, type
, dstsuper
, dsttype
, &cost
, program
) != 6)
2470 if (!warn
&& !errors
&& !verbose
)
2471 _cupsLangPuts(stdout
, _(" FAIL"));
2474 _cupsLangPrintf(stdout
,
2475 _(" %s Bad cupsFilter2 value \"%s\"."),
2476 prefix
, attr
->value
);
2481 else if (strcmp(program
, "-"))
2483 if (strncmp(program
, "maxsize(", 8) &&
2484 (ptr
= strchr(program
+ 8, ')')) != NULL
)
2487 while (_cups_isspace(*ptr
))
2490 _cups_strcpy(program
, ptr
);
2493 if (program
[0] == '/')
2494 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2497 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2498 ptr
= CUPS_SERVERBIN
;
2500 if (*ptr
== '/' || !*root
)
2501 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2504 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2508 if (stat(pathprog
, &fileinfo
))
2510 if (!warn
&& !errors
&& !verbose
)
2511 _cupsLangPuts(stdout
, _(" FAIL"));
2514 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2515 prefix
, "cupsFilter2", pathprog
);
2520 else if (fileinfo
.st_uid
!= 0 ||
2521 (fileinfo
.st_mode
& MODE_WRITE
) ||
2522 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2524 if (!warn
&& !errors
&& !verbose
)
2525 _cupsLangPuts(stdout
, _(" FAIL"));
2528 _cupsLangPrintf(stdout
,
2529 _(" %s Bad permissions on %s file \"%s\"."),
2530 prefix
, "cupsFilter2", pathprog
);
2536 errors
= valid_path("cupsFilter2", pathprog
, errors
, verbose
, warn
);
2544 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2546 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2548 if (strcmp(attr
->name
, "cupsPreFilter"))
2550 if (!warn
&& !errors
&& !verbose
)
2551 _cupsLangPuts(stdout
, _(" FAIL"));
2554 _cupsLangPrintf(stdout
,
2555 _(" %s Bad spelling of %s - should be %s."),
2556 prefix
, attr
->name
, "cupsPreFilter");
2563 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2564 &cost
, program
) != 4)
2566 if (!warn
&& !errors
&& !verbose
)
2567 _cupsLangPuts(stdout
, _(" FAIL"));
2570 _cupsLangPrintf(stdout
,
2571 _(" %s Bad cupsPreFilter value \"%s\"."),
2572 prefix
, attr
->value
? attr
->value
: "");
2577 else if (strcmp(program
, "-"))
2579 if (program
[0] == '/')
2580 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2583 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2584 ptr
= CUPS_SERVERBIN
;
2586 if (*ptr
== '/' || !*root
)
2587 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2590 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2594 if (stat(pathprog
, &fileinfo
))
2596 if (!warn
&& !errors
&& !verbose
)
2597 _cupsLangPuts(stdout
, _(" FAIL"));
2600 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2601 prefix
, "cupsPreFilter", pathprog
);
2606 else if (fileinfo
.st_uid
!= 0 ||
2607 (fileinfo
.st_mode
& MODE_WRITE
) ||
2608 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2610 if (!warn
&& !errors
&& !verbose
)
2611 _cupsLangPuts(stdout
, _(" FAIL"));
2614 _cupsLangPrintf(stdout
,
2615 _(" %s Bad permissions on %s file \"%s\"."),
2616 prefix
, "cupsPreFilter", pathprog
);
2622 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2631 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2633 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2635 if (strcmp(attr
->name
, "APDialogExtension"))
2637 if (!warn
&& !errors
&& !verbose
)
2638 _cupsLangPuts(stdout
, _(" FAIL"));
2641 _cupsLangPrintf(stdout
,
2642 _(" %s Bad spelling of %s - should be %s."),
2643 prefix
, attr
->name
, "APDialogExtension");
2649 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2650 attr
->value
? attr
->value
: "(null)");
2652 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2654 if (!warn
&& !errors
&& !verbose
)
2655 _cupsLangPuts(stdout
, _(" FAIL"));
2658 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2659 prefix
, "APDialogExtension", pathprog
);
2664 else if (fileinfo
.st_uid
!= 0 ||
2665 (fileinfo
.st_mode
& MODE_WRITE
) ||
2666 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2668 if (!warn
&& !errors
&& !verbose
)
2669 _cupsLangPuts(stdout
, _(" FAIL"));
2672 _cupsLangPrintf(stdout
,
2673 _(" %s Bad permissions on %s file \"%s\"."),
2674 prefix
, "APDialogExtension", pathprog
);
2680 errors
= valid_path("APDialogExtension", pathprog
, errors
, verbose
,
2688 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2690 if (strcmp(attr
->name
, "APPrinterIconPath"))
2692 if (!warn
&& !errors
&& !verbose
)
2693 _cupsLangPuts(stdout
, _(" FAIL"));
2696 _cupsLangPrintf(stdout
,
2697 _(" %s Bad spelling of %s - should be %s."),
2698 prefix
, attr
->name
, "APPrinterIconPath");
2704 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2705 attr
->value
? attr
->value
: "(null)");
2707 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2709 if (!warn
&& !errors
&& !verbose
)
2710 _cupsLangPuts(stdout
, _(" FAIL"));
2713 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2714 prefix
, "APPrinterIconPath", pathprog
);
2719 else if (fileinfo
.st_uid
!= 0 ||
2720 (fileinfo
.st_mode
& MODE_WRITE
) ||
2721 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2723 if (!warn
&& !errors
&& !verbose
)
2724 _cupsLangPuts(stdout
, _(" FAIL"));
2727 _cupsLangPrintf(stdout
,
2728 _(" %s Bad permissions on %s file \"%s\"."),
2729 prefix
, "APPrinterIconPath", pathprog
);
2735 errors
= valid_path("APPrinterIconPath", pathprog
, errors
, verbose
,
2740 * APPrinterLowInkTool
2743 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2745 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2747 if (!warn
&& !errors
&& !verbose
)
2748 _cupsLangPuts(stdout
, _(" FAIL"));
2751 _cupsLangPrintf(stdout
,
2752 _(" %s Bad spelling of %s - should be %s."),
2753 prefix
, attr
->name
, "APPrinterLowInkTool");
2759 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2760 attr
->value
? attr
->value
: "(null)");
2762 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2764 if (!warn
&& !errors
&& !verbose
)
2765 _cupsLangPuts(stdout
, _(" FAIL"));
2768 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2769 prefix
, "APPrinterLowInkTool", pathprog
);
2774 else if (fileinfo
.st_uid
!= 0 ||
2775 (fileinfo
.st_mode
& MODE_WRITE
) ||
2776 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2778 if (!warn
&& !errors
&& !verbose
)
2779 _cupsLangPuts(stdout
, _(" FAIL"));
2782 _cupsLangPrintf(stdout
,
2783 _(" %s Bad permissions on %s file \"%s\"."),
2784 prefix
, "APPrinterLowInkTool", pathprog
);
2790 errors
= valid_path("APPrinterLowInkTool", pathprog
, errors
, verbose
,
2795 * APPrinterUtilityPath
2798 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2800 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2802 if (!warn
&& !errors
&& !verbose
)
2803 _cupsLangPuts(stdout
, _(" FAIL"));
2806 _cupsLangPrintf(stdout
,
2807 _(" %s Bad spelling of %s - should be %s."),
2808 prefix
, attr
->name
, "APPrinterUtilityPath");
2814 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2815 attr
->value
? attr
->value
: "(null)");
2817 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2819 if (!warn
&& !errors
&& !verbose
)
2820 _cupsLangPuts(stdout
, _(" FAIL"));
2823 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2824 prefix
, "APPrinterUtilityPath", pathprog
);
2829 else if (fileinfo
.st_uid
!= 0 ||
2830 (fileinfo
.st_mode
& MODE_WRITE
) ||
2831 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2833 if (!warn
&& !errors
&& !verbose
)
2834 _cupsLangPuts(stdout
, _(" FAIL"));
2837 _cupsLangPrintf(stdout
,
2838 _(" %s Bad permissions on %s file \"%s\"."),
2839 prefix
, "APPrinterUtilityPath", pathprog
);
2845 errors
= valid_path("APPrinterUtilityPath", pathprog
, errors
, verbose
,
2850 * APScanAppBundleID and APScanAppPath
2853 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2855 if (strcmp(attr
->name
, "APScanAppPath"))
2857 if (!warn
&& !errors
&& !verbose
)
2858 _cupsLangPuts(stdout
, _(" FAIL"));
2861 _cupsLangPrintf(stdout
,
2862 _(" %s Bad spelling of %s - should be %s."),
2863 prefix
, attr
->name
, "APScanAppPath");
2869 if (!attr
->value
|| stat(attr
->value
, &fileinfo
))
2871 if (!warn
&& !errors
&& !verbose
)
2872 _cupsLangPuts(stdout
, _(" FAIL"));
2875 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2876 prefix
, "APScanAppPath",
2877 attr
->value
? attr
->value
: "<NULL>");
2882 else if (fileinfo
.st_uid
!= 0 ||
2883 (fileinfo
.st_mode
& MODE_WRITE
) ||
2884 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2886 if (!warn
&& !errors
&& !verbose
)
2887 _cupsLangPuts(stdout
, _(" FAIL"));
2890 _cupsLangPrintf(stdout
,
2891 _(" %s Bad permissions on %s file \"%s\"."),
2892 prefix
, "APScanAppPath", attr
->value
);
2898 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2901 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2903 if (!warn
&& !errors
&& !verbose
)
2904 _cupsLangPuts(stdout
, _(" FAIL"));
2907 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2908 "APScanAppPath and APScanAppBundleID."),
2915 #endif /* __APPLE__ */
2922 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2925 static int /* O - Errors found */
2926 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2927 const char *root
, /* I - Root directory */
2928 int errors
, /* I - Errors found */
2929 int verbose
, /* I - Verbosity level */
2930 int warn
) /* I - Warnings only? */
2932 int i
; /* Looping var */
2933 ppd_attr_t
*attr
; /* PPD attribute */
2934 const char *ptr
; /* Pointer into string */
2935 const char *prefix
; /* WARN/FAIL prefix */
2936 char filename
[1024]; /* Profile filename */
2937 struct stat fileinfo
; /* File information */
2938 int num_profiles
= 0; /* Number of profiles */
2939 unsigned hash
, /* Current hash value */
2940 hashes
[1000]; /* Hash values of profile names */
2941 const char *specs
[1000]; /* Specifiers for profiles */
2944 prefix
= warn
? " WARN " : "**FAIL**";
2946 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
2948 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
2951 * Check for valid selector...
2954 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
2957 if (!attr
->value
|| i
< 2)
2959 if (!warn
&& !errors
&& !verbose
)
2960 _cupsLangPuts(stdout
, _(" FAIL"));
2963 _cupsLangPrintf(stdout
,
2964 _(" %s Bad cupsICCProfile %s."),
2965 prefix
, attr
->spec
);
2974 * Check for valid profile filename...
2977 if (attr
->value
[0] == '/')
2978 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
2981 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
2984 if (*ptr
== '/' || !*root
)
2985 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
2988 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
2992 if (stat(filename
, &fileinfo
))
2994 if (!warn
&& !errors
&& !verbose
)
2995 _cupsLangPuts(stdout
, _(" FAIL"));
2998 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2999 prefix
, "cupsICCProfile", filename
);
3004 else if (fileinfo
.st_uid
!= 0 ||
3005 (fileinfo
.st_mode
& MODE_WRITE
) ||
3006 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
3008 if (!warn
&& !errors
&& !verbose
)
3009 _cupsLangPuts(stdout
, _(" FAIL"));
3012 _cupsLangPrintf(stdout
,
3013 _(" %s Bad permissions on %s file \"%s\"."),
3014 prefix
, "cupsICCProfile", filename
);
3020 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
3023 * Check for hash collisions...
3026 hash
= _ppdHashName(attr
->spec
);
3028 if (num_profiles
> 0)
3030 for (i
= 0; i
< num_profiles
; i
++)
3031 if (hashes
[i
] == hash
)
3034 if (i
< num_profiles
)
3036 if (!warn
&& !errors
&& !verbose
)
3037 _cupsLangPuts(stdout
, _(" FAIL"));
3040 _cupsLangPrintf(stdout
,
3041 _(" %s cupsICCProfile %s hash value "
3042 "collides with %s."), prefix
, attr
->spec
,
3051 * Remember up to 1000 profiles...
3054 if (num_profiles
< 1000)
3056 hashes
[num_profiles
] = hash
;
3057 specs
[num_profiles
] = attr
->spec
;
3067 * 'check_sizes()' - Check media sizes in the PPD file.
3070 static int /* O - Errors found */
3071 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
3072 int errors
, /* I - Errors found */
3073 int verbose
, /* I - Verbosity level */
3074 int warn
) /* I - Warnings only? */
3076 int i
; /* Looping var */
3077 ppd_size_t
*size
; /* Current size */
3078 int width
, /* Custom width */
3079 length
; /* Custom length */
3080 const char *prefix
; /* WARN/FAIL prefix */
3081 ppd_option_t
*page_size
, /* PageSize option */
3082 *page_region
; /* PageRegion option */
3083 _pwg_media_t
*pwg_media
; /* PWG media */
3084 char buf
[PPD_MAX_NAME
]; /* PapeSize name that is supposed to be */
3085 const char *ptr
; /* Pointer into string */
3086 int width_2540ths
, /* PageSize width in 2540ths */
3087 length_2540ths
; /* PageSize length in 2540ths */
3088 int is_ok
; /* Flag for PageSize name verification */
3089 double width_tmp
, /* Width after rounded up */
3090 length_tmp
, /* Length after rounded up */
3091 width_inch
, /* Width in inches */
3092 length_inch
, /* Length in inches */
3093 width_mm
, /* Width in millimeters */
3094 length_mm
; /* Length in millimeters */
3097 prefix
= warn
? " WARN " : "**FAIL**";
3099 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
3101 if (!warn
&& !errors
&& !verbose
)
3102 _cupsLangPuts(stdout
, _(" FAIL"));
3105 _cupsLangPrintf(stdout
,
3106 _(" %s Missing REQUIRED PageSize option.\n"
3107 " REF: Page 99, section 5.14."),
3114 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
3116 if (!warn
&& !errors
&& !verbose
)
3117 _cupsLangPuts(stdout
, _(" FAIL"));
3120 _cupsLangPrintf(stdout
,
3121 _(" %s Missing REQUIRED PageRegion option.\n"
3122 " REF: Page 100, section 5.14."),
3129 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
3132 * Check that the size name is standard...
3135 if (!strcmp(size
->name
, "Custom"))
3138 * Skip custom page size...
3144 if (warn
!= 2 && size
->name
[0] == 'w' &&
3145 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
3148 * Validate device-specific size wNNNhNNN should have proper width and
3152 if (fabs(width
- size
->width
) >= 1.0 ||
3153 fabs(length
- size
->length
) >= 1.0)
3155 if (!warn
&& !errors
&& !verbose
)
3156 _cupsLangPuts(stdout
, _(" FAIL"));
3159 _cupsLangPrintf(stdout
,
3160 _(" %s Size \"%s\" has unexpected dimensions "
3162 prefix
, size
->name
, size
->width
, size
->length
);
3170 * Verify that the size is defined for both PageSize and PageRegion...
3173 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
3175 if (!warn
&& !errors
&& !verbose
)
3176 _cupsLangPuts(stdout
, _(" FAIL"));
3179 _cupsLangPrintf(stdout
,
3180 _(" %s Size \"%s\" defined for %s but not for "
3182 prefix
, size
->name
, "PageRegion", "PageSize");
3187 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3189 if (!warn
&& !errors
&& !verbose
)
3190 _cupsLangPuts(stdout
, _(" FAIL"));
3193 _cupsLangPrintf(stdout
,
3194 _(" %s Size \"%s\" defined for %s but not for "
3196 prefix
, size
->name
, "PageSize", "PageRegion");
3203 * Verify that the size name is Adobe standard name if it's a standard size
3204 * and the dimentional name if it's not a standard size. Suffix should be
3205 * .Fullbleed, etc., or numeric, e.g., Letter, Letter.Fullbleed,
3206 * Letter.Transverse, Letter1, Letter2, 4x8, 55x91mm, 55x91mm.Fullbleed, etc.
3212 width_2540ths
= (size
->length
> size
->width
) ?
3213 PWG_FROM_POINTS(size
->width
) :
3214 PWG_FROM_POINTS(size
->length
);
3215 length_2540ths
= (size
->length
> size
->width
) ?
3216 PWG_FROM_POINTS(size
->length
) :
3217 PWG_FROM_POINTS(size
->width
);
3218 pwg_media
= pwgMediaForSize(width_2540ths
, length_2540ths
);
3221 (fabs(pwg_media
->width
- width_2540ths
) > 34 ||
3222 fabs(pwg_media
->length
- length_2540ths
) > 34))
3223 pwg_media
= NULL
; /* Only flag matches within a point */
3225 if (pwg_media
&& pwg_media
->ppd
&&
3226 (pwg_media
->ppd
[0] < 'a' || pwg_media
->ppd
[0] > 'z'))
3228 size_t ppdlen
= strlen(pwg_media
->ppd
);
3229 /* Length of standard PPD name */
3231 strlcpy(buf
, pwg_media
->ppd
, sizeof(buf
));
3233 if (strcmp(size
->name
, buf
) && size
->width
> size
->length
)
3235 if (!strcmp(pwg_media
->ppd
, "DoublePostcardRotated"))
3236 strlcpy(buf
, "DoublePostcard", sizeof(buf
));
3237 else if (strstr(size
->name
, ".Transverse"))
3238 snprintf(buf
, sizeof(buf
), "%s.Transverse", pwg_media
->ppd
);
3240 snprintf(buf
, sizeof(buf
), "%sRotated", pwg_media
->ppd
);
3242 ppdlen
= strlen(buf
);
3245 if (size
->left
== 0 && size
->bottom
== 0 &&
3246 size
->right
== size
->width
&& size
->top
== size
->length
)
3248 strlcat(buf
, ".Fullbleed", sizeof(buf
) - strlen(buf
));
3249 if (_cups_strcasecmp(size
->name
, buf
))
3252 * Allow an additional qualifier such as ".WithTab"...
3255 size_t buflen
= strlen(buf
);/* Length of full bleed name */
3257 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3258 size
->name
[buflen
] != '.')
3262 else if (!strncmp(size
->name
, pwg_media
->ppd
, ppdlen
))
3265 * Check for a proper qualifier (number, "Small", or .something)...
3268 ptr
= size
->name
+ ppdlen
;
3270 if (isdigit(*ptr
& 255))
3272 for (ptr
++; *ptr
; ptr
++)
3274 if (!isdigit(*ptr
& 255))
3281 else if (*ptr
!= '.' && *ptr
&& strcmp(ptr
, "Small"))
3287 * Check for EnvSizeName as well...
3290 if (strncmp(pwg_media
->ppd
, "Env", 3) &&
3291 !strncmp(size
->name
, "Env", 3))
3292 snprintf(buf
, sizeof(buf
), "Env%s", pwg_media
->ppd
);
3294 if (strcmp(size
->name
, buf
))
3299 _cupsLangPrintf(stdout
,
3300 _(" %s Size \"%s\" should be the Adobe "
3301 "standard name \"%s\"."),
3302 prefix
, size
->name
, buf
);
3306 width_tmp
= (fabs(size
->width
- ceil(size
->width
)) < 0.1) ?
3307 ceil(size
->width
) : size
->width
;
3308 length_tmp
= (fabs(size
->length
- ceil(size
->length
)) < 0.1) ?
3309 ceil(size
->length
) : size
->length
;
3311 if (fmod(width_tmp
, 9.0) == 0.0 && fmod(length_tmp
, 9.0) == 0.0)
3313 width_inch
= width_tmp
/ 72.0;
3314 length_inch
= length_tmp
/ 72.0;
3316 snprintf(buf
, sizeof(buf
), "%gx%g", width_inch
, length_inch
);
3320 width_mm
= size
->width
/ 72.0 * 25.4;
3321 length_mm
= size
->length
/ 72.0 * 25.4;
3323 snprintf(buf
, sizeof(buf
), "%.0fx%.0fmm", width_mm
, length_mm
);
3326 if (size
->left
== 0 && size
->bottom
== 0 &&
3327 size
->right
== size
->width
&& size
->top
== size
->length
)
3328 strlcat(buf
, ".Fullbleed", sizeof(buf
));
3329 else if (size
->width
> size
->length
)
3330 strlcat(buf
, ".Transverse", sizeof(buf
));
3332 if (_cups_strcasecmp(size
->name
, buf
))
3334 size_t buflen
= strlen(buf
);
3335 /* Length of proposed name */
3337 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3338 (strcmp(size
->name
+ buflen
, "in") &&
3339 size
->name
[buflen
] != '.'))
3341 char altbuf
[PPD_MAX_NAME
];
3342 /* Alternate "wNNNhNNN" name */
3343 size_t altlen
; /* Length of alternate name */
3345 snprintf(altbuf
, sizeof(altbuf
), "w%.0fh%.0f", size
->width
,
3347 altlen
= strlen(altbuf
);
3348 if (_cups_strncasecmp(size
->name
, altbuf
, altlen
) ||
3349 (size
->name
[altlen
] && size
->name
[altlen
] != '.'))
3350 _cupsLangPrintf(stdout
,
3351 _(" %s Size \"%s\" should be \"%s\"."),
3352 prefix
, size
->name
, buf
);
3364 * 'check_translations()' - Check translations in the PPD file.
3367 static int /* O - Errors found */
3368 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3369 int errors
, /* I - Errors found */
3370 int verbose
, /* I - Verbosity level */
3371 int warn
) /* I - Warnings only? */
3373 int j
; /* Looping var */
3374 ppd_attr_t
*attr
; /* PPD attribute */
3375 cups_array_t
*languages
; /* Array of languages */
3376 int langlen
; /* Length of language */
3377 char *language
, /* Current language */
3378 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3379 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3380 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3381 cllkeyword
[PPD_MAX_NAME
];
3382 /* Custom option keyword (base) */
3383 ppd_option_t
*option
; /* Standard UI option */
3384 ppd_coption_t
*coption
; /* Custom option */
3385 ppd_cparam_t
*cparam
; /* Custom parameter */
3386 char ll
[3]; /* Base language */
3387 const char *prefix
; /* WARN/FAIL prefix */
3388 const char *text
; /* Pointer into UI text */
3391 prefix
= warn
? " WARN " : "**FAIL**";
3393 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3396 * This file contains localizations, check them...
3399 for (language
= (char *)cupsArrayFirst(languages
);
3401 language
= (char *)cupsArrayNext(languages
))
3403 langlen
= (int)strlen(language
);
3404 if (langlen
!= 2 && langlen
!= 5)
3406 if (!warn
&& !errors
&& !verbose
)
3407 _cupsLangPuts(stdout
, _(" FAIL"));
3410 _cupsLangPrintf(stdout
,
3411 _(" %s Bad language \"%s\"."),
3420 if (!strcmp(language
, "en"))
3423 strlcpy(ll
, language
, sizeof(ll
));
3426 * Loop through all options and choices...
3429 for (option
= ppdFirstOption(ppd
);
3431 option
= ppdNextOption(ppd
))
3433 if (!strcmp(option
->keyword
, "PageRegion"))
3436 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3437 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3439 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3440 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3442 if (!warn
&& !errors
&& !verbose
)
3443 _cupsLangPuts(stdout
, _(" FAIL"));
3446 _cupsLangPrintf(stdout
,
3447 _(" %s Missing \"%s\" translation "
3448 "string for option %s."),
3449 prefix
, language
, option
->keyword
);
3454 else if (!valid_utf8(attr
->text
))
3456 if (!warn
&& !errors
&& !verbose
)
3457 _cupsLangPuts(stdout
, _(" FAIL"));
3460 _cupsLangPrintf(stdout
,
3461 _(" %s Bad UTF-8 \"%s\" translation "
3462 "string for option %s."),
3463 prefix
, language
, option
->keyword
);
3469 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3471 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3474 for (j
= 0; j
< option
->num_choices
; j
++)
3477 * First see if this choice is a number; if so, don't require
3481 for (text
= option
->choices
[j
].text
; *text
; text
++)
3482 if (!strchr("0123456789-+.", *text
))
3489 * Check custom choices differently...
3492 if (!_cups_strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3493 (coption
= ppdFindCustomOption(ppd
,
3494 option
->keyword
)) != NULL
)
3496 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3497 language
, option
->keyword
);
3499 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3500 !valid_utf8(attr
->text
))
3502 if (!warn
&& !errors
&& !verbose
)
3503 _cupsLangPuts(stdout
, _(" FAIL"));
3506 _cupsLangPrintf(stdout
,
3507 _(" %s Bad UTF-8 \"%s\" "
3508 "translation string for option %s, "
3511 ckeyword
+ 1 + strlen(language
),
3518 if (_cups_strcasecmp(option
->keyword
, "PageSize"))
3520 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3522 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3524 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3525 language
, option
->keyword
);
3526 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3527 ll
, option
->keyword
);
3529 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3530 cparam
->name
)) == NULL
&&
3531 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3532 cparam
->name
)) == NULL
)
3534 if (!warn
&& !errors
&& !verbose
)
3535 _cupsLangPuts(stdout
, _(" FAIL"));
3538 _cupsLangPrintf(stdout
,
3539 _(" %s Missing \"%s\" "
3540 "translation string for option %s, "
3543 ckeyword
+ 1 + strlen(language
),
3549 else if (!valid_utf8(attr
->text
))
3551 if (!warn
&& !errors
&& !verbose
)
3552 _cupsLangPuts(stdout
, _(" FAIL"));
3555 _cupsLangPrintf(stdout
,
3556 _(" %s Bad UTF-8 \"%s\" "
3557 "translation string for option %s, "
3560 ckeyword
+ 1 + strlen(language
),
3569 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3570 option
->choices
[j
].choice
)) == NULL
&&
3571 (attr
= ppdFindAttr(ppd
, llkeyword
,
3572 option
->choices
[j
].choice
)) == NULL
)
3574 if (!warn
&& !errors
&& !verbose
)
3575 _cupsLangPuts(stdout
, _(" FAIL"));
3578 _cupsLangPrintf(stdout
,
3579 _(" %s Missing \"%s\" "
3580 "translation string for option %s, "
3582 prefix
, language
, option
->keyword
,
3583 option
->choices
[j
].choice
);
3588 else if (!valid_utf8(attr
->text
))
3590 if (!warn
&& !errors
&& !verbose
)
3591 _cupsLangPuts(stdout
, _(" FAIL"));
3594 _cupsLangPrintf(stdout
,
3595 _(" %s Bad UTF-8 \"%s\" "
3596 "translation string for option %s, "
3598 prefix
, language
, option
->keyword
,
3599 option
->choices
[j
].choice
);
3609 * Verify that we have the base language for each localized one...
3612 for (language
= (char *)cupsArrayFirst(languages
);
3614 language
= (char *)cupsArrayNext(languages
))
3618 * Lookup the base language...
3621 cupsArraySave(languages
);
3623 strlcpy(ll
, language
, sizeof(ll
));
3625 if (!cupsArrayFind(languages
, ll
) &&
3626 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3628 if (!warn
&& !errors
&& !verbose
)
3629 _cupsLangPuts(stdout
, _(" FAIL"));
3632 _cupsLangPrintf(stdout
,
3633 _(" %s No base translation \"%s\" "
3634 "is included in file."), prefix
, ll
);
3640 cupsArrayRestore(languages
);
3644 * Free memory used for the languages...
3647 _ppdFreeLanguages(languages
);
3655 * 'show_conflicts()' - Show option conflicts in a PPD file.
3659 show_conflicts(ppd_file_t
*ppd
, /* I - PPD to check */
3660 const char *prefix
) /* I - Prefix string */
3662 int i
, j
; /* Looping variables */
3663 ppd_const_t
*c
; /* Current constraint */
3664 ppd_option_t
*o1
, *o2
; /* Options */
3665 ppd_choice_t
*c1
, *c2
; /* Choices */
3669 * Loop through all of the UI constraints and report any options
3673 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3676 * Grab pointers to the first option...
3679 o1
= ppdFindOption(ppd
, c
->option1
);
3683 else if (c
->choice1
[0] != '\0')
3686 * This constraint maps to a specific choice.
3689 c1
= ppdFindChoice(o1
, c
->choice1
);
3694 * This constraint applies to any choice for this option.
3697 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3702 !_cups_strcasecmp(c1
->choice
, "None") ||
3703 !_cups_strcasecmp(c1
->choice
, "Off") ||
3704 !_cups_strcasecmp(c1
->choice
, "False"))
3709 * Grab pointers to the second option...
3712 o2
= ppdFindOption(ppd
, c
->option2
);
3716 else if (c
->choice2
[0] != '\0')
3719 * This constraint maps to a specific choice.
3722 c2
= ppdFindChoice(o2
, c
->choice2
);
3727 * This constraint applies to any choice for this option.
3730 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3735 !_cups_strcasecmp(c2
->choice
, "None") ||
3736 !_cups_strcasecmp(c2
->choice
, "Off") ||
3737 !_cups_strcasecmp(c2
->choice
, "False"))
3742 * If both options are marked then there is a conflict...
3745 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3746 _cupsLangPrintf(stdout
,
3747 _(" %s \"%s %s\" conflicts with \"%s %s\"\n"
3748 " (constraint=\"%s %s %s %s\")."),
3749 prefix
, o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3750 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3756 * 'test_raster()' - Test PostScript commands for raster printers.
3759 static int /* O - 1 on success, 0 on failure */
3760 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3761 int verbose
) /* I - Verbosity */
3763 cups_page_header2_t header
; /* Page header */
3766 ppdMarkDefaults(ppd
);
3767 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3770 _cupsLangPuts(stdout
, _(" FAIL"));
3773 _cupsLangPrintf(stdout
,
3774 _(" **FAIL** Default option code cannot be "
3775 "interpreted: %s"), cupsRasterErrorString());
3781 * Try a test of custom page size code, if available...
3784 if (!ppdPageSize(ppd
, "Custom.612x792"))
3787 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3789 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3792 _cupsLangPuts(stdout
, _(" FAIL"));
3795 _cupsLangPrintf(stdout
,
3796 _(" **FAIL** Default option code cannot be "
3797 "interpreted: %s"), cupsRasterErrorString());
3807 * 'usage()' - Show program usage.
3813 _cupsLangPuts(stdout
, _("Usage: cupstestppd [options] filename1.ppd[.gz] "
3814 "[... filenameN.ppd[.gz]]"));
3815 _cupsLangPuts(stdout
, _(" program | cupstestppd [options] -"));
3816 _cupsLangPuts(stdout
, "");
3817 _cupsLangPuts(stdout
, _("Options:"));
3818 _cupsLangPuts(stdout
, "");
3819 _cupsLangPuts(stdout
, _(" -I {filename,filters,none,profiles}"));
3820 _cupsLangPuts(stdout
, _(" Ignore specific warnings."));
3821 _cupsLangPuts(stdout
, _(" -R root-directory Set alternate root."));
3822 _cupsLangPuts(stdout
, _(" -W {all,none,constraints,defaults,duplex,"
3823 "filters,profiles,sizes,translations}"));
3824 _cupsLangPuts(stdout
, _(" Issue warnings instead of "
3826 _cupsLangPuts(stdout
, _(" -q Run silently."));
3827 _cupsLangPuts(stdout
, _(" -r Use 'relaxed' open mode."));
3828 _cupsLangPuts(stdout
, _(" -v Be verbose."));
3829 _cupsLangPuts(stdout
, _(" -vv Be very verbose."));
3836 * 'valid_path()' - Check whether a path has the correct capitalization.
3839 static int /* O - Errors found */
3840 valid_path(const char *keyword
, /* I - Keyword using path */
3841 const char *path
, /* I - Path to check */
3842 int errors
, /* I - Errors found */
3843 int verbose
, /* I - Verbosity level */
3844 int warn
) /* I - Warnings only? */
3846 cups_dir_t
*dir
; /* Current directory */
3847 cups_dentry_t
*dentry
; /* Current directory entry */
3848 char temp
[1024], /* Temporary path */
3849 *ptr
; /* Pointer into temporary path */
3850 const char *prefix
; /* WARN/FAIL prefix */
3853 prefix
= warn
? " WARN " : "**FAIL**";
3856 * Loop over the components of the path, checking that the entry exists with
3857 * the same capitalization...
3860 strlcpy(temp
, path
, sizeof(temp
));
3862 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3865 * Chop off the trailing component so temp == dirname and ptr == basename.
3871 * Try opening the directory containing the base name...
3875 dir
= cupsDirOpen(temp
);
3877 dir
= cupsDirOpen("/");
3883 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3885 if (!strcmp(dentry
->filename
, ptr
))
3893 * Display an error if the filename doesn't exist with the same
3899 if (!warn
&& !errors
&& !verbose
)
3900 _cupsLangPuts(stdout
, _(" FAIL"));
3903 _cupsLangPrintf(stdout
,
3904 _(" %s %s file \"%s\" has the wrong "
3905 "capitalization."), prefix
, keyword
, path
);
3919 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3922 static int /* O - 1 if valid, 0 if not */
3923 valid_utf8(const char *s
) /* I - String to check */
3930 * Check for valid UTF-8 sequence...
3933 if ((*s
& 0xc0) == 0x80)
3934 return (0); /* Illegal suffix byte */
3935 else if ((*s
& 0xe0) == 0xc0)
3938 * 2-byte sequence...
3943 if ((*s
& 0xc0) != 0x80)
3944 return (0); /* Missing suffix byte */
3946 else if ((*s
& 0xf0) == 0xe0)
3949 * 3-byte sequence...
3954 if ((*s
& 0xc0) != 0x80)
3955 return (0); /* Missing suffix byte */
3959 if ((*s
& 0xc0) != 0x80)
3960 return (0); /* Missing suffix byte */
3962 else if ((*s
& 0xf8) == 0xf0)
3965 * 4-byte sequence...
3970 if ((*s
& 0xc0) != 0x80)
3971 return (0); /* Missing suffix byte */
3975 if ((*s
& 0xc0) != 0x80)
3976 return (0); /* Missing suffix byte */
3980 if ((*s
& 0xc0) != 0x80)
3981 return (0); /* Missing suffix byte */
3984 return (0); /* Bad sequence */