2 * PPD test program for CUPS.
4 * THIS PROGRAM IS DEPRECATED AND WILL BE REMOVED IN A FUTURE VERSION OF CUPS.
6 * Copyright © 2007-2018 by Apple Inc.
7 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
9 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * PostScript is a trademark of Adobe Systems, Inc.
16 * Include necessary headers...
19 #include <cups/cups-private.h>
21 #include <cups/ppd-private.h>
22 #include <cups/raster.h>
30 * Error warning overrides...
40 WARN_TRANSLATIONS
= 16,
79 #define MODE_WRITE 0022 /* Group/other write */
80 #define MODE_MASK 0555 /* Owner/group/other read+exec/search */
81 #define MODE_DATAFILE 0444 /* Owner/group/other read */
82 #define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
83 #define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
90 static void check_basics(const char *filename
);
91 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
93 static int check_case(ppd_file_t
*ppd
, int errors
, int verbose
);
94 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
96 static int check_duplex(ppd_file_t
*ppd
, int errors
, int verbose
,
98 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
99 int verbose
, int warn
);
100 static int check_profiles(ppd_file_t
*ppd
, const char *root
, int errors
,
101 int verbose
, int warn
);
102 static int check_sizes(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
103 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,
105 static void show_conflicts(ppd_file_t
*ppd
, const char *prefix
);
106 static int test_raster(ppd_file_t
*ppd
, int verbose
);
107 static void usage(void) _CUPS_NORETURN
;
108 static int valid_path(const char *keyword
, const char *path
, int errors
,
109 int verbose
, int warn
);
110 static int valid_utf8(const char *s
);
114 * 'main()' - Main entry for test program.
117 int /* O - Exit status */
118 main(int argc
, /* I - Number of command-line args */
119 char *argv
[]) /* I - Command-line arguments */
121 int i
, j
, k
, m
, n
; /* Looping vars */
122 size_t len
; /* Length of option name */
123 char *opt
; /* Option character */
124 const char *ptr
; /* Pointer into string */
125 cups_file_t
*fp
; /* PPD file */
126 int files
; /* Number of files */
127 int verbose
; /* Want verbose output? */
128 int warn
; /* Which errors to just warn about */
129 int ignore
; /* Which errors to ignore */
130 int status
; /* Exit status */
131 int errors
; /* Number of conformance errors */
132 int ppdversion
; /* PPD spec version in PPD file */
133 ppd_status_t error
; /* Status of ppdOpen*() */
134 int line
; /* Line number for error */
135 char *root
; /* Root directory */
136 int xdpi
, /* X resolution */
137 ydpi
; /* Y resolution */
138 ppd_file_t
*ppd
; /* PPD file record */
139 ppd_attr_t
*attr
; /* PPD attribute */
140 ppd_size_t
*size
; /* Size record */
141 ppd_group_t
*group
; /* UI group */
142 ppd_option_t
*option
; /* Standard UI option */
143 ppd_group_t
*group2
; /* UI group */
144 ppd_option_t
*option2
; /* Standard UI option */
145 ppd_choice_t
*choice
; /* Standard UI option choice */
146 struct lconv
*loc
; /* Locale data */
147 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
148 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
149 "JCL", "PAGE", "PROLOG" };
152 _cupsSetLocale(argv
);
156 * Display PPD files for each file listed on the command-line...
159 ppdSetConformance(PPD_CONFORM_STRICT
);
169 for (i
= 1; i
< argc
; i
++)
170 if (!strcmp(argv
[i
], "--help"))
172 else if (argv
[i
][0] == '-' && argv
[i
][1])
174 for (opt
= argv
[i
] + 1; *opt
; opt
++)
177 case 'I' : /* Ignore errors */
183 if (!strcmp(argv
[i
], "none"))
185 else if (!strcmp(argv
[i
], "filename"))
186 ignore
|= WARN_FILENAME
;
187 else if (!strcmp(argv
[i
], "filters"))
188 ignore
|= WARN_FILTERS
;
189 else if (!strcmp(argv
[i
], "profiles"))
190 ignore
|= WARN_PROFILES
;
191 else if (!strcmp(argv
[i
], "all"))
192 ignore
= WARN_FILTERS
| WARN_PROFILES
;
197 case 'R' : /* Alternate root directory */
206 case 'W' : /* Turn errors into warnings */
212 if (!strcmp(argv
[i
], "none"))
214 else if (!strcmp(argv
[i
], "constraints"))
215 warn
|= WARN_CONSTRAINTS
;
216 else if (!strcmp(argv
[i
], "defaults"))
217 warn
|= WARN_DEFAULTS
;
218 else if (!strcmp(argv
[i
], "duplex"))
220 else if (!strcmp(argv
[i
], "filters"))
221 warn
|= WARN_FILTERS
;
222 else if (!strcmp(argv
[i
], "profiles"))
223 warn
|= WARN_PROFILES
;
224 else if (!strcmp(argv
[i
], "sizes"))
226 else if (!strcmp(argv
[i
], "translations"))
227 warn
|= WARN_TRANSLATIONS
;
228 else if (!strcmp(argv
[i
], "all"))
234 case 'q' : /* Quiet mode */
237 _cupsLangPuts(stderr
,
238 _("cupstestppd: The -q option is incompatible "
239 "with the -v option."));
246 case 'r' : /* Relaxed mode */
247 ppdSetConformance(PPD_CONFORM_RELAXED
);
250 case 'v' : /* Verbose mode */
253 _cupsLangPuts(stderr
,
254 _("cupstestppd: The -v option is incompatible "
255 "with the -q option."));
269 * Open the PPD file...
272 if (files
&& verbose
>= 0)
277 if (argv
[i
][0] == '-')
283 ppd
= _ppdOpen(cupsFileStdin(), _PPD_LOCALIZATION_ALL
);
286 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
291 * Read from a file...
295 printf("%s:", argv
[i
]);
297 if ((fp
= cupsFileOpen(argv
[i
], "r")) != NULL
)
299 ppd
= _ppdOpen(fp
, _PPD_LOCALIZATION_ALL
);
304 status
= ERROR_FILE_OPEN
;
308 _cupsLangPuts(stdout
, _(" FAIL"));
309 _cupsLangPrintf(stdout
,
310 _(" **FAIL** Unable to open PPD file - %s on "
311 "line %d."), strerror(errno
), 0);
319 error
= ppdLastError(&line
);
321 if (error
<= PPD_ALLOC_ERROR
)
323 status
= ERROR_FILE_OPEN
;
327 _cupsLangPuts(stdout
, _(" FAIL"));
328 _cupsLangPrintf(stdout
,
329 _(" **FAIL** Unable to open PPD file - %s on "
330 "line %d."), strerror(errno
), 0);
335 status
= ERROR_PPD_FORMAT
;
339 _cupsLangPuts(stdout
, _(" FAIL"));
340 _cupsLangPrintf(stdout
,
341 _(" **FAIL** Unable to open PPD file - "
343 ppdErrorString(error
), line
);
347 case PPD_MISSING_PPDADOBE4
:
348 _cupsLangPuts(stdout
,
349 _(" REF: Page 42, section "
352 case PPD_MISSING_VALUE
:
353 _cupsLangPuts(stdout
,
354 _(" REF: Page 20, section "
357 case PPD_BAD_OPEN_GROUP
:
358 case PPD_NESTED_OPEN_GROUP
:
359 _cupsLangPuts(stdout
,
360 _(" REF: Pages 45-46, section "
363 case PPD_BAD_OPEN_UI
:
364 case PPD_NESTED_OPEN_UI
:
365 _cupsLangPuts(stdout
,
366 _(" REF: Pages 42-45, section "
369 case PPD_BAD_ORDER_DEPENDENCY
:
370 _cupsLangPuts(stdout
,
371 _(" REF: Pages 48-49, section "
374 case PPD_BAD_UI_CONSTRAINTS
:
375 _cupsLangPuts(stdout
,
376 _(" REF: Pages 52-54, section "
379 case PPD_MISSING_ASTERISK
:
380 _cupsLangPuts(stdout
,
381 _(" REF: Page 15, section "
384 case PPD_LINE_TOO_LONG
:
385 _cupsLangPuts(stdout
,
386 _(" REF: Page 15, section "
389 case PPD_ILLEGAL_CHARACTER
:
390 _cupsLangPuts(stdout
,
391 _(" REF: Page 15, section "
394 case PPD_ILLEGAL_MAIN_KEYWORD
:
395 _cupsLangPuts(stdout
,
396 _(" REF: Pages 16-17, section "
399 case PPD_ILLEGAL_OPTION_KEYWORD
:
400 _cupsLangPuts(stdout
,
401 _(" REF: Page 19, section "
404 case PPD_ILLEGAL_TRANSLATION
:
405 _cupsLangPuts(stdout
,
406 _(" REF: Page 27, section "
413 check_basics(argv
[i
]);
421 * Show the header and then perform basic conformance tests (limited
422 * only by what the CUPS PPD functions actually load...)
429 _cupsLangPuts(stdout
,
430 _("\n DETAILED CONFORMANCE TEST RESULTS"));
432 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
434 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
436 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) != NULL
)
440 if (strstr(attr
->value
, "application/vnd.cups-raster"))
442 if (!test_raster(ppd
, verbose
))
447 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
451 for (j
= 0; j
< ppd
->num_filters
; j
++)
452 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
454 if (!test_raster(ppd
, verbose
))
461 * Look for default keywords with no matching option...
464 if (!(warn
& WARN_DEFAULTS
))
465 errors
= check_defaults(ppd
, errors
, verbose
, 0);
467 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
471 if (!errors
&& !verbose
)
472 _cupsLangPuts(stdout
, _(" FAIL"));
474 _cupsLangPuts(stdout
,
475 _(" **FAIL** REQUIRED DefaultImageableArea\n"
476 " REF: Page 102, section 5.15."));
481 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
482 strcmp(attr
->value
, "Unknown"))
486 if (!errors
&& !verbose
)
487 _cupsLangPuts(stdout
, _(" FAIL"));
489 _cupsLangPrintf(stdout
,
490 _(" **FAIL** Bad DefaultImageableArea %s\n"
491 " REF: Page 102, section 5.15."),
500 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea"));
503 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
507 if (!errors
&& !verbose
)
508 _cupsLangPuts(stdout
, _(" FAIL"));
510 _cupsLangPuts(stdout
,
511 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
512 " REF: Page 103, section 5.15."));
517 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
518 strcmp(attr
->value
, "Unknown"))
522 if (!errors
&& !verbose
)
523 _cupsLangPuts(stdout
, _(" FAIL"));
525 _cupsLangPrintf(stdout
,
526 _(" **FAIL** Bad DefaultPaperDimension %s\n"
527 " REF: Page 103, section 5.15."),
533 else if (verbose
> 0)
534 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension"));
536 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
537 for (k
= 0, option
= group
->options
;
538 k
< group
->num_options
;
542 * Verify that we have a default choice...
545 if (option
->defchoice
[0])
547 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
548 strcmp(option
->defchoice
, "Unknown"))
552 if (!errors
&& !verbose
)
553 _cupsLangPuts(stdout
, _(" FAIL"));
555 _cupsLangPrintf(stdout
,
556 _(" **FAIL** Bad Default%s %s\n"
557 " REF: Page 40, section 4.5."),
558 option
->keyword
, option
->defchoice
);
563 else if (verbose
> 0)
564 _cupsLangPrintf(stdout
,
565 _(" PASS Default%s"),
572 if (!errors
&& !verbose
)
573 _cupsLangPuts(stdout
, _(" FAIL"));
575 _cupsLangPrintf(stdout
,
576 _(" **FAIL** REQUIRED Default%s\n"
577 " REF: Page 40, section 4.5."),
585 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
587 for (ptr
= attr
->value
; *ptr
; ptr
++)
588 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
595 if (!errors
&& !verbose
)
596 _cupsLangPuts(stdout
, _(" FAIL"));
598 _cupsLangPrintf(stdout
,
599 _(" **FAIL** Bad FileVersion \"%s\"\n"
600 " REF: Page 56, section 5.3."),
606 else if (verbose
> 0)
607 _cupsLangPuts(stdout
, _(" PASS FileVersion"));
613 if (!errors
&& !verbose
)
614 _cupsLangPuts(stdout
, _(" FAIL"));
616 _cupsLangPuts(stdout
,
617 _(" **FAIL** REQUIRED FileVersion\n"
618 " REF: Page 56, section 5.3."));
624 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
627 if (*ptr
== '4' && ptr
[1] == '.')
630 for (ptr
+= 2; *ptr
; ptr
++)
631 if (!isdigit(*ptr
& 255))
639 if (!errors
&& !verbose
)
640 _cupsLangPuts(stdout
, _(" FAIL"));
642 _cupsLangPrintf(stdout
,
643 _(" **FAIL** Bad FormatVersion \"%s\"\n"
644 " REF: Page 56, section 5.3."),
650 else if (verbose
> 0)
651 _cupsLangPuts(stdout
, _(" PASS FormatVersion"));
657 if (!errors
&& !verbose
)
658 _cupsLangPuts(stdout
, _(" FAIL"));
660 _cupsLangPuts(stdout
,
661 _(" **FAIL** REQUIRED FormatVersion\n"
662 " REF: Page 56, section 5.3."));
668 if (ppd
->lang_encoding
!= NULL
)
671 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding"));
673 else if (ppdversion
> 40)
677 if (!errors
&& !verbose
)
678 _cupsLangPuts(stdout
, _(" FAIL"));
680 _cupsLangPuts(stdout
,
681 _(" **FAIL** REQUIRED LanguageEncoding\n"
682 " REF: Pages 56-57, section 5.3."));
688 if (ppd
->lang_version
!= NULL
)
691 _cupsLangPuts(stdout
, _(" PASS LanguageVersion"));
697 if (!errors
&& !verbose
)
698 _cupsLangPuts(stdout
, _(" FAIL"));
700 _cupsLangPuts(stdout
,
701 _(" **FAIL** REQUIRED LanguageVersion\n"
702 " REF: Pages 57-58, section 5.3."));
708 if (ppd
->manufacturer
!= NULL
)
710 if (!_cups_strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
711 !_cups_strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
715 if (!errors
&& !verbose
)
716 _cupsLangPuts(stdout
, _(" FAIL"));
718 _cupsLangPrintf(stdout
,
719 _(" **FAIL** Bad Manufacturer (should be "
721 " REF: Page 211, table D.1."),
727 else if (!_cups_strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
728 !_cups_strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
732 if (!errors
&& !verbose
)
733 _cupsLangPuts(stdout
, _(" FAIL"));
735 _cupsLangPrintf(stdout
,
736 _(" **FAIL** Bad Manufacturer (should be "
738 " REF: Page 211, table D.1."),
744 else if (verbose
> 0)
745 _cupsLangPuts(stdout
, _(" PASS Manufacturer"));
747 else if (ppdversion
>= 43)
751 if (!errors
&& !verbose
)
752 _cupsLangPuts(stdout
, _(" FAIL"));
754 _cupsLangPuts(stdout
,
755 _(" **FAIL** REQUIRED Manufacturer\n"
756 " REF: Pages 58-59, section 5.3."));
762 if (ppd
->modelname
!= NULL
)
764 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
765 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
772 if (!errors
&& !verbose
)
773 _cupsLangPuts(stdout
, _(" FAIL"));
775 _cupsLangPrintf(stdout
,
776 _(" **FAIL** Bad ModelName - \"%c\" not "
777 "allowed in string.\n"
778 " REF: Pages 59-60, section 5.3."),
784 else if (verbose
> 0)
785 _cupsLangPuts(stdout
, _(" PASS ModelName"));
791 if (!errors
&& !verbose
)
792 _cupsLangPuts(stdout
, _(" FAIL"));
794 _cupsLangPuts(stdout
,
795 _(" **FAIL** REQUIRED ModelName\n"
796 " REF: Pages 59-60, section 5.3."));
802 if (ppd
->nickname
!= NULL
)
805 _cupsLangPuts(stdout
, _(" PASS NickName"));
811 if (!errors
&& !verbose
)
812 _cupsLangPuts(stdout
, _(" FAIL"));
814 _cupsLangPuts(stdout
,
815 _(" **FAIL** REQUIRED NickName\n"
816 " REF: Page 60, section 5.3."));
822 if (ppdFindOption(ppd
, "PageSize") != NULL
)
825 _cupsLangPuts(stdout
, _(" PASS PageSize"));
831 if (!errors
&& !verbose
)
832 _cupsLangPuts(stdout
, _(" FAIL"));
834 _cupsLangPuts(stdout
,
835 _(" **FAIL** REQUIRED PageSize\n"
836 " REF: Pages 99-100, section 5.14."));
842 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
845 _cupsLangPuts(stdout
, _(" PASS PageRegion"));
851 if (!errors
&& !verbose
)
852 _cupsLangPuts(stdout
, _(" FAIL"));
854 _cupsLangPuts(stdout
,
855 _(" **FAIL** REQUIRED PageRegion\n"
856 " REF: Page 100, section 5.14."));
862 if (ppd
->pcfilename
!= NULL
)
865 _cupsLangPuts(stdout
, _(" PASS PCFileName"));
867 else if (!(ignore
& WARN_FILENAME
))
871 if (!errors
&& !verbose
)
872 _cupsLangPuts(stdout
, _(" FAIL"));
874 _cupsLangPuts(stdout
,
875 _(" **FAIL** REQUIRED PCFileName\n"
876 " REF: Pages 61-62, section 5.3."));
882 if (ppd
->product
!= NULL
)
884 if (ppd
->product
[0] != '(' ||
885 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
889 if (!errors
&& !verbose
)
890 _cupsLangPuts(stdout
, _(" FAIL"));
892 _cupsLangPuts(stdout
,
893 _(" **FAIL** Bad Product - not \"(string)\".\n"
894 " REF: Page 62, section 5.3."));
899 else if (verbose
> 0)
900 _cupsLangPuts(stdout
, _(" PASS Product"));
906 if (!errors
&& !verbose
)
907 _cupsLangPuts(stdout
, _(" FAIL"));
909 _cupsLangPuts(stdout
,
910 _(" **FAIL** REQUIRED Product\n"
911 " REF: Page 62, section 5.3."));
917 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
920 char junkstr
[255]; /* Temp string */
921 int junkint
; /* Temp integer */
924 if (sscanf(attr
->value
, "(%254[^)\n])%d", junkstr
, &junkint
) != 2)
928 if (!errors
&& !verbose
)
929 _cupsLangPuts(stdout
, _(" FAIL"));
931 _cupsLangPuts(stdout
,
932 _(" **FAIL** Bad PSVersion - not \"(string) "
934 " REF: Pages 62-64, section 5.3."));
939 else if (verbose
> 0)
940 _cupsLangPuts(stdout
, _(" PASS PSVersion"));
946 if (!errors
&& !verbose
)
947 _cupsLangPuts(stdout
, _(" FAIL"));
949 _cupsLangPuts(stdout
,
950 _(" **FAIL** REQUIRED PSVersion\n"
951 " REF: Pages 62-64, section 5.3."));
957 if (ppd
->shortnickname
!= NULL
)
959 if (strlen(ppd
->shortnickname
) > 31)
963 if (!errors
&& !verbose
)
964 _cupsLangPuts(stdout
, _(" FAIL"));
966 _cupsLangPuts(stdout
,
967 _(" **FAIL** Bad ShortNickName - longer "
969 " REF: Pages 64-65, section 5.3."));
974 else if (verbose
> 0)
975 _cupsLangPuts(stdout
, _(" PASS ShortNickName"));
977 else if (ppdversion
>= 43)
981 if (!errors
&& !verbose
)
982 _cupsLangPuts(stdout
, _(" FAIL"));
984 _cupsLangPuts(stdout
,
985 _(" **FAIL** REQUIRED ShortNickName\n"
986 " REF: Page 64-65, section 5.3."));
992 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
993 strstr(ppd
->patches
, "*End"))
997 if (!errors
&& !verbose
)
998 _cupsLangPuts(stdout
, _(" FAIL"));
1000 _cupsLangPuts(stdout
,
1001 _(" **FAIL** Bad JobPatchFile attribute in file\n"
1002 " REF: Page 24, section 3.4."));
1009 * Check for page sizes without the corresponding ImageableArea or
1010 * PaperDimension values...
1013 if (ppd
->num_sizes
== 0)
1017 if (!errors
&& !verbose
)
1018 _cupsLangPuts(stdout
, _(" FAIL"));
1020 _cupsLangPuts(stdout
,
1021 _(" **FAIL** REQUIRED PageSize\n"
1022 " REF: Page 41, section 5.\n"
1023 " REF: Page 99, section 5.14."));
1030 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1033 * Don't check custom size...
1036 if (!strcmp(size
->name
, "Custom"))
1040 * Check for ImageableArea...
1043 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1044 size
->right
== 0.0 && size
->top
== 0.0)
1048 if (!errors
&& !verbose
)
1049 _cupsLangPuts(stdout
, _(" FAIL"));
1051 _cupsLangPrintf(stdout
,
1052 _(" **FAIL** REQUIRED ImageableArea for "
1054 " REF: Page 41, section 5.\n"
1055 " REF: Page 102, section 5.15."),
1063 * Check for PaperDimension...
1066 if (size
->width
<= 0.0 && size
->length
<= 0.0)
1070 if (!errors
&& !verbose
)
1071 _cupsLangPuts(stdout
, _(" FAIL"));
1073 _cupsLangPrintf(stdout
,
1074 _(" **FAIL** REQUIRED PaperDimension "
1076 " REF: Page 41, section 5.\n"
1077 " REF: Page 103, section 5.15."),
1087 * Check for valid Resolution, JCLResolution, or SetResolution values...
1090 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1091 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1092 option
= ppdFindOption(ppd
, "SetResolution");
1096 for (j
= option
->num_choices
, choice
= option
->choices
;
1101 * Verify that all resolution options are of the form NNNdpi
1105 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1106 if (ptr
> choice
->choice
&& xdpi
> 0)
1109 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1116 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1121 if (!errors
&& !verbose
)
1122 _cupsLangPuts(stdout
, _(" FAIL"));
1124 _cupsLangPrintf(stdout
,
1125 _(" **FAIL** Bad option %s choice %s\n"
1126 " REF: Page 84, section 5.9"),
1127 option
->keyword
, choice
->choice
);
1135 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1136 strcmp(attr
->name
, "1284DeviceID"))
1140 if (!errors
&& !verbose
)
1141 _cupsLangPuts(stdout
, _(" FAIL"));
1143 _cupsLangPrintf(stdout
,
1144 _(" **FAIL** %s must be 1284DeviceID\n"
1145 " REF: Page 72, section 5.5"),
1152 errors
= check_case(ppd
, errors
, verbose
);
1154 if (!(warn
& WARN_CONSTRAINTS
))
1155 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1157 if (!(warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1158 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1160 if (!(warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1161 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1163 if (!(warn
& WARN_SIZES
))
1164 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1166 if (!(warn
& WARN_TRANSLATIONS
))
1167 errors
= check_translations(ppd
, errors
, verbose
, 0);
1169 if (!(warn
& WARN_DUPLEX
))
1170 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1172 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1176 * This file contains localizations, check for conformance of the
1177 * base translation...
1180 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1182 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1184 if (!errors
&& !verbose
)
1185 _cupsLangPuts(stdout
, _(" FAIL"));
1188 _cupsLangPrintf(stdout
,
1189 _(" **FAIL** Bad LanguageEncoding %s - "
1190 "must be ISOLatin1."),
1191 attr
->value
? attr
->value
: "(null)");
1196 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1198 if (!errors
&& !verbose
)
1199 _cupsLangPuts(stdout
, _(" FAIL"));
1202 _cupsLangPrintf(stdout
,
1203 _(" **FAIL** Bad LanguageVersion %s - "
1204 "must be English."),
1205 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1211 * Loop through all options and choices...
1214 for (option
= ppdFirstOption(ppd
);
1216 option
= ppdNextOption(ppd
))
1219 * Check for special characters outside A0 to BF, F7, or F8
1220 * that are used for languages other than English.
1223 for (ptr
= option
->text
; *ptr
; ptr
++)
1224 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1225 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1230 if (!errors
&& !verbose
)
1231 _cupsLangPuts(stdout
, _(" FAIL"));
1234 _cupsLangPrintf(stdout
,
1235 _(" **FAIL** Default translation "
1236 "string for option %s contains 8-bit "
1243 for (j
= 0; j
< option
->num_choices
; j
++)
1246 * Check for special characters outside A0 to BF, F7, or F8
1247 * that are used for languages other than English.
1250 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1251 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1252 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1257 if (!errors
&& !verbose
)
1258 _cupsLangPuts(stdout
, _(" FAIL"));
1261 _cupsLangPrintf(stdout
,
1262 _(" **FAIL** Default translation "
1263 "string for option %s choice %s contains "
1264 "8-bit characters."),
1266 option
->choices
[j
].choice
);
1276 * Final pass/fail notification...
1280 status
= ERROR_CONFORMANCE
;
1282 _cupsLangPuts(stdout
, _(" PASS"));
1286 check_basics(argv
[i
]);
1288 if (warn
& WARN_DEFAULTS
)
1289 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1291 if (warn
& WARN_CONSTRAINTS
)
1292 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1294 if ((warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1295 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1297 if ((warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1298 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1300 if (warn
& WARN_SIZES
)
1301 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1303 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1305 if (warn
& WARN_TRANSLATIONS
)
1306 errors
= check_translations(ppd
, errors
, verbose
, 1);
1308 if (warn
& WARN_DUPLEX
)
1309 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1312 * Look for legacy duplex keywords...
1315 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1316 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1317 option
= ppdFindOption(ppd
, "KD03Duplex");
1320 _cupsLangPrintf(stdout
,
1321 _(" WARN Duplex option keyword %s may not "
1322 "work as expected and should be named Duplex.\n"
1323 " REF: Page 122, section 5.17"),
1327 * Look for default keywords with no corresponding option...
1330 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1332 attr
= ppd
->attrs
[j
];
1334 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1335 !strcmp(attr
->name
, "DefaultColorSep") ||
1336 !strcmp(attr
->name
, "DefaultFont") ||
1337 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1338 !strcmp(attr
->name
, "DefaultImageableArea") ||
1339 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1340 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1341 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1342 !strcmp(attr
->name
, "DefaultResolution") ||
1343 !strcmp(attr
->name
, "DefaultScreenProc") ||
1344 !strcmp(attr
->name
, "DefaultTransfer"))
1347 if (!strncmp(attr
->name
, "Default", 7) &&
1348 !ppdFindOption(ppd
, attr
->name
+ 7))
1349 _cupsLangPrintf(stdout
,
1350 _(" WARN %s has no corresponding "
1355 if (ppdversion
< 43)
1357 _cupsLangPrintf(stdout
,
1358 _(" WARN Obsolete PPD version %.1f.\n"
1359 " REF: Page 42, section 5.2."),
1363 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1365 _cupsLangPuts(stdout
,
1366 _(" WARN LanguageEncoding required by PPD "
1368 " REF: Pages 56-57, section 5.3."));
1371 if (!ppd
->manufacturer
&& ppdversion
< 43)
1373 _cupsLangPuts(stdout
,
1374 _(" WARN Manufacturer required by PPD "
1376 " REF: Pages 58-59, section 5.3."));
1380 * Treat a PCFileName attribute longer than 12 characters as
1381 * a warning and not a hard error...
1384 if (!(ignore
& WARN_FILENAME
) && ppd
->pcfilename
)
1386 if (strlen(ppd
->pcfilename
) > 12)
1388 _cupsLangPuts(stdout
,
1389 _(" WARN PCFileName longer than 8.3 in "
1390 "violation of PPD spec.\n"
1391 " REF: Pages 61-62, section "
1395 if (!_cups_strcasecmp(ppd
->pcfilename
, "unused.ppd"))
1396 _cupsLangPuts(stdout
,
1397 _(" WARN PCFileName should contain a "
1398 "unique filename.\n"
1399 " REF: Pages 61-62, section "
1403 if (!ppd
->shortnickname
&& ppdversion
< 43)
1405 _cupsLangPuts(stdout
,
1406 _(" WARN ShortNickName required by PPD "
1408 " REF: Pages 64-65, section 5.3."));
1412 * Check the Protocols line and flag PJL + BCP since TBCP is
1413 * usually used with PJL...
1418 if (strstr(ppd
->protocols
, "PJL") &&
1419 strstr(ppd
->protocols
, "BCP") &&
1420 !strstr(ppd
->protocols
, "TBCP"))
1422 _cupsLangPuts(stdout
,
1423 _(" WARN Protocols contains both PJL "
1424 "and BCP; expected TBCP.\n"
1425 " REF: Pages 78-79, section 5.7."));
1428 if (strstr(ppd
->protocols
, "PJL") &&
1429 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1431 _cupsLangPuts(stdout
,
1432 _(" WARN Protocols contains PJL but JCL "
1433 "attributes are not set.\n"
1434 " REF: Pages 78-79, section 5.7."));
1439 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1440 * which are errors according to the spec but won't cause problems
1441 * with CUPS specifically...
1444 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1445 for (k
= 0, option
= group
->options
;
1446 k
< group
->num_options
;
1449 len
= strlen(option
->keyword
);
1451 for (m
= 0, group2
= ppd
->groups
;
1452 m
< ppd
->num_groups
;
1454 for (n
= 0, option2
= group2
->options
;
1455 n
< group2
->num_options
;
1457 if (option
!= option2
&&
1458 len
< strlen(option2
->keyword
) &&
1459 !strncmp(option
->keyword
, option2
->keyword
, len
))
1461 _cupsLangPrintf(stdout
,
1462 _(" WARN %s shares a common "
1464 " REF: Page 15, section "
1466 option
->keyword
, option2
->keyword
);
1474 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND"), errors
);
1476 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND"));
1480 * Then list the options, if "-v" was provided...
1485 _cupsLangPrintf(stdout
,
1487 " language_level = %d\n"
1488 " color_device = %s\n"
1489 " variable_sizes = %s\n"
1491 ppd
->language_level
,
1492 ppd
->color_device
? "TRUE" : "FALSE",
1493 ppd
->variable_sizes
? "TRUE" : "FALSE",
1496 switch (ppd
->colorspace
)
1499 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK");
1502 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY");
1505 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY");
1508 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB");
1511 _cupsLangPuts(stdout
, " colorspace = <unknown>");
1515 _cupsLangPrintf(stdout
, " num_emulations = %d",
1516 ppd
->num_emulations
);
1517 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1518 _cupsLangPrintf(stdout
, " emulations[%d] = %s",
1519 j
, ppd
->emulations
[j
].name
);
1521 _cupsLangPrintf(stdout
, " lang_encoding = %s",
1522 ppd
->lang_encoding
);
1523 _cupsLangPrintf(stdout
, " lang_version = %s",
1525 _cupsLangPrintf(stdout
, " modelname = %s", ppd
->modelname
);
1526 _cupsLangPrintf(stdout
, " ttrasterizer = %s",
1527 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1528 _cupsLangPrintf(stdout
, " manufacturer = %s",
1530 _cupsLangPrintf(stdout
, " product = %s", ppd
->product
);
1531 _cupsLangPrintf(stdout
, " nickname = %s", ppd
->nickname
);
1532 _cupsLangPrintf(stdout
, " shortnickname = %s",
1533 ppd
->shortnickname
);
1534 _cupsLangPrintf(stdout
, " patches = %d bytes",
1535 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1537 _cupsLangPrintf(stdout
, " num_groups = %d", ppd
->num_groups
);
1538 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1540 _cupsLangPrintf(stdout
, " group[%d] = %s",
1543 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1545 _cupsLangPrintf(stdout
,
1546 " options[%d] = %s (%s) %s %s %.0f "
1548 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1549 sections
[option
->section
], option
->order
,
1550 option
->num_choices
);
1552 if (!strcmp(option
->keyword
, "PageSize") ||
1553 !strcmp(option
->keyword
, "PageRegion"))
1555 for (m
= option
->num_choices
, choice
= option
->choices
;
1559 size
= ppdPageSize(ppd
, choice
->choice
);
1562 _cupsLangPrintf(stdout
,
1563 " %s (%s) = ERROR%s",
1564 choice
->choice
, choice
->text
,
1565 !strcmp(option
->defchoice
, choice
->choice
)
1568 _cupsLangPrintf(stdout
,
1569 " %s (%s) = %.2fx%.2fin "
1570 "(%.1f,%.1f,%.1f,%.1f)%s",
1571 choice
->choice
, choice
->text
,
1572 size
->width
/ 72.0, size
->length
/ 72.0,
1573 size
->left
/ 72.0, size
->bottom
/ 72.0,
1574 size
->right
/ 72.0, size
->top
/ 72.0,
1575 !strcmp(option
->defchoice
, choice
->choice
)
1581 for (m
= option
->num_choices
, choice
= option
->choices
;
1585 _cupsLangPrintf(stdout
, " %s (%s)%s",
1586 choice
->choice
, choice
->text
,
1587 !strcmp(option
->defchoice
, choice
->choice
)
1594 _cupsLangPrintf(stdout
, " num_consts = %d",
1596 for (j
= 0; j
< ppd
->num_consts
; j
++)
1597 _cupsLangPrintf(stdout
,
1598 " consts[%d] = *%s %s *%s %s",
1599 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1600 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1602 _cupsLangPrintf(stdout
, " num_profiles = %d",
1604 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1605 _cupsLangPrintf(stdout
,
1606 " profiles[%d] = %s/%s %.3f %.3f "
1607 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]",
1608 j
, ppd
->profiles
[j
].resolution
,
1609 ppd
->profiles
[j
].media_type
,
1610 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1611 ppd
->profiles
[j
].matrix
[0][0],
1612 ppd
->profiles
[j
].matrix
[0][1],
1613 ppd
->profiles
[j
].matrix
[0][2],
1614 ppd
->profiles
[j
].matrix
[1][0],
1615 ppd
->profiles
[j
].matrix
[1][1],
1616 ppd
->profiles
[j
].matrix
[1][2],
1617 ppd
->profiles
[j
].matrix
[2][0],
1618 ppd
->profiles
[j
].matrix
[2][1],
1619 ppd
->profiles
[j
].matrix
[2][2]);
1621 _cupsLangPrintf(stdout
, " num_fonts = %d", ppd
->num_fonts
);
1622 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1623 _cupsLangPrintf(stdout
, " fonts[%d] = %s",
1626 _cupsLangPrintf(stdout
, " num_attrs = %d", ppd
->num_attrs
);
1627 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1628 _cupsLangPrintf(stdout
,
1629 " attrs[%d] = %s %s%s%s: \"%s\"", j
,
1630 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1631 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1632 ppd
->attrs
[j
]->text
,
1633 ppd
->attrs
[j
]->value
?
1634 ppd
->attrs
[j
]->value
: "(null)");
1648 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1652 check_basics(const char *filename
) /* I - PPD file to check */
1654 cups_file_t
*fp
; /* File pointer */
1655 int ch
; /* Current character */
1656 int col
, /* Current column */
1657 whitespace
; /* Only seen whitespace? */
1658 int eol
; /* Line endings */
1659 int linenum
; /* Line number */
1660 int mixed
; /* Mixed line endings? */
1663 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1672 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1674 if (ch
== '\r' || ch
== '\n')
1678 if (eol
== EOL_NONE
)
1680 else if (eol
!= EOL_LF
)
1683 else if (ch
== '\r')
1685 if (cupsFilePeekChar(fp
) == '\n')
1687 cupsFileGetChar(fp
);
1689 if (eol
== EOL_NONE
)
1691 else if (eol
!= EOL_CRLF
)
1694 else if (eol
== EOL_NONE
)
1696 else if (eol
!= EOL_CR
)
1700 if (col
> 0 && whitespace
)
1701 _cupsLangPrintf(stdout
,
1702 _(" WARN Line %d only contains whitespace."),
1711 if (ch
!= ' ' && ch
!= '\t')
1719 _cupsLangPuts(stdout
,
1720 _(" WARN File contains a mix of CR, LF, and "
1721 "CR LF line endings."));
1723 if (eol
== EOL_CRLF
)
1724 _cupsLangPuts(stdout
,
1725 _(" WARN Non-Windows PPD files should use lines "
1726 "ending with only LF, not CR LF."));
1733 * 'check_constraints()' - Check UIConstraints in the PPD file.
1736 static int /* O - Errors found */
1737 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1738 int errors
, /* I - Errors found */
1739 int verbose
, /* I - Verbosity level */
1740 int warn
) /* I - Warnings only? */
1742 int i
; /* Looping var */
1743 const char *prefix
; /* WARN/FAIL prefix */
1744 ppd_const_t
*c
; /* Current UIConstraints data */
1745 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1746 const char *vptr
; /* Pointer into constraint value */
1747 char option
[PPD_MAX_NAME
],
1748 /* Option name/MainKeyword */
1749 choice
[PPD_MAX_NAME
],
1750 /* Choice/OptionKeyword */
1751 *ptr
; /* Pointer into option or choice */
1752 int num_options
; /* Number of options */
1753 cups_option_t
*options
; /* Options */
1754 ppd_option_t
*o
; /* PPD option */
1757 prefix
= warn
? " WARN " : "**FAIL**";
1761 * See what kind of constraint data we have in the PPD...
1764 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1767 * Check new-style cupsUIConstraints data...
1771 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1773 if (!constattr
->value
)
1775 if (!warn
&& !errors
&& !verbose
)
1776 _cupsLangPuts(stdout
, _(" FAIL"));
1778 _cupsLangPrintf(stdout
,
1779 _(" %s Empty cupsUIConstraints %s"),
1780 prefix
, constattr
->spec
);
1788 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1790 i
++, vptr
= strchr(vptr
+ 1, '*'));
1794 if (!warn
&& !errors
&& !verbose
)
1795 _cupsLangPuts(stdout
, _(" FAIL"));
1797 _cupsLangPrintf(stdout
,
1798 _(" %s Bad cupsUIConstraints %s: \"%s\""),
1799 prefix
, constattr
->spec
, constattr
->value
);
1807 cupsArraySave(ppd
->sorted_attrs
);
1809 if (constattr
->spec
[0] &&
1810 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1812 if (!warn
&& !errors
&& !verbose
)
1813 _cupsLangPuts(stdout
, _(" FAIL"));
1815 _cupsLangPrintf(stdout
,
1816 _(" %s Missing cupsUIResolver %s"),
1817 prefix
, constattr
->spec
);
1823 cupsArrayRestore(ppd
->sorted_attrs
);
1828 for (vptr
= strchr(constattr
->value
, '*');
1830 vptr
= strchr(vptr
, '*'))
1833 * Extract "*Option Choice" or just "*Option"...
1836 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1837 if (ptr
< (option
+ sizeof(option
) - 1))
1842 while (isspace(*vptr
& 255))
1849 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1850 if (ptr
< (choice
+ sizeof(choice
) - 1))
1856 if (!_cups_strncasecmp(option
, "Custom", 6) && !_cups_strcasecmp(choice
, "True"))
1858 _cups_strcpy(option
, option
+ 6);
1859 strlcpy(choice
, "Custom", sizeof(choice
));
1862 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1864 if (!warn
&& !errors
&& !verbose
)
1865 _cupsLangPuts(stdout
, _(" FAIL"));
1867 _cupsLangPrintf(stdout
,
1868 _(" %s Missing option %s in "
1869 "cupsUIConstraints %s: \"%s\""),
1870 prefix
, option
, constattr
->spec
, constattr
->value
);
1878 if (choice
[0] && !ppdFindChoice(o
, choice
))
1880 if (!warn
&& !errors
&& !verbose
)
1881 _cupsLangPuts(stdout
, _(" FAIL"));
1883 _cupsLangPrintf(stdout
,
1884 _(" %s Missing choice *%s %s in "
1885 "cupsUIConstraints %s: \"%s\""),
1886 prefix
, option
, choice
, constattr
->spec
,
1896 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1899 for (i
= 0; i
< o
->num_choices
; i
++)
1900 if (_cups_strcasecmp(o
->choices
[i
].choice
, "None") &&
1901 _cups_strcasecmp(o
->choices
[i
].choice
, "Off") &&
1902 _cups_strcasecmp(o
->choices
[i
].choice
, "False"))
1904 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
1905 num_options
, &options
);
1912 * Resolvers must list at least two options...
1915 if (num_options
< 2)
1917 if (!warn
&& !errors
&& !verbose
)
1918 _cupsLangPuts(stdout
, _(" FAIL"));
1920 _cupsLangPrintf(stdout
,
1921 _(" %s cupsUIResolver %s does not list at least "
1922 "two different options."),
1923 prefix
, constattr
->spec
);
1930 * Test the resolver...
1933 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
1935 if (!warn
&& !errors
&& !verbose
)
1936 _cupsLangPuts(stdout
, _(" FAIL"));
1938 _cupsLangPrintf(stdout
,
1939 _(" %s cupsUIResolver %s causes a loop."),
1940 prefix
, constattr
->spec
);
1946 cupsFreeOptions(num_options
, options
);
1952 * Check old-style [Non]UIConstraints data...
1955 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1957 if (!_cups_strncasecmp(c
->option1
, "Custom", 6) &&
1958 !_cups_strcasecmp(c
->choice1
, "True"))
1960 strlcpy(option
, c
->option1
+ 6, sizeof(option
));
1961 strlcpy(choice
, "Custom", sizeof(choice
));
1965 strlcpy(option
, c
->option1
, sizeof(option
));
1966 strlcpy(choice
, c
->choice1
, sizeof(choice
));
1969 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1971 if (!warn
&& !errors
&& !verbose
)
1972 _cupsLangPuts(stdout
, _(" FAIL"));
1974 _cupsLangPrintf(stdout
,
1975 _(" %s Missing option %s in "
1976 "UIConstraints \"*%s %s *%s %s\"."),
1978 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1983 else if (choice
[0] && !ppdFindChoice(o
, choice
))
1985 if (!warn
&& !errors
&& !verbose
)
1986 _cupsLangPuts(stdout
, _(" FAIL"));
1988 _cupsLangPrintf(stdout
,
1989 _(" %s Missing choice *%s %s in "
1990 "UIConstraints \"*%s %s *%s %s\"."),
1991 prefix
, c
->option1
, c
->choice1
,
1992 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1998 if (!_cups_strncasecmp(c
->option2
, "Custom", 6) &&
1999 !_cups_strcasecmp(c
->choice2
, "True"))
2001 strlcpy(option
, c
->option2
+ 6, sizeof(option
));
2002 strlcpy(choice
, "Custom", sizeof(choice
));
2006 strlcpy(option
, c
->option2
, sizeof(option
));
2007 strlcpy(choice
, c
->choice2
, sizeof(choice
));
2010 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
2012 if (!warn
&& !errors
&& !verbose
)
2013 _cupsLangPuts(stdout
, _(" FAIL"));
2015 _cupsLangPrintf(stdout
,
2016 _(" %s Missing option %s in "
2017 "UIConstraints \"*%s %s *%s %s\"."),
2019 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2024 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2026 if (!warn
&& !errors
&& !verbose
)
2027 _cupsLangPuts(stdout
, _(" FAIL"));
2029 _cupsLangPrintf(stdout
,
2030 _(" %s Missing choice *%s %s in "
2031 "UIConstraints \"*%s %s *%s %s\"."),
2032 prefix
, c
->option2
, c
->choice2
,
2033 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2046 * 'check_case()' - Check that there are no duplicate groups, options,
2047 * or choices that differ only by case.
2050 static int /* O - Errors found */
2051 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2052 int errors
, /* I - Errors found */
2053 int verbose
) /* I - Verbosity level */
2055 int i
, j
; /* Looping vars */
2056 ppd_group_t
*groupa
, /* First group */
2057 *groupb
; /* Second group */
2058 ppd_option_t
*optiona
, /* First option */
2059 *optionb
; /* Second option */
2060 ppd_choice_t
*choicea
, /* First choice */
2061 *choiceb
; /* Second choice */
2065 * Check that the groups do not have any duplicate names...
2068 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2069 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2070 if (!_cups_strcasecmp(groupa
->name
, groupb
->name
))
2072 if (!errors
&& !verbose
)
2073 _cupsLangPuts(stdout
, _(" FAIL"));
2076 _cupsLangPrintf(stdout
,
2077 _(" **FAIL** Group names %s and %s differ only "
2079 groupa
->name
, groupb
->name
);
2085 * Check that the options do not have any duplicate names...
2088 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2090 cupsArraySave(ppd
->options
);
2091 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2092 if (!_cups_strcasecmp(optiona
->keyword
, optionb
->keyword
))
2094 if (!errors
&& !verbose
)
2095 _cupsLangPuts(stdout
, _(" FAIL"));
2098 _cupsLangPrintf(stdout
,
2099 _(" **FAIL** Option names %s and %s differ only "
2101 optiona
->keyword
, optionb
->keyword
);
2105 cupsArrayRestore(ppd
->options
);
2108 * Then the choices...
2111 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2114 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2115 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2117 if (!errors
&& !verbose
)
2118 _cupsLangPuts(stdout
, _(" FAIL"));
2121 _cupsLangPrintf(stdout
,
2122 _(" **FAIL** Multiple occurrences of "
2123 "option %s choice name %s."),
2124 optiona
->keyword
, choicea
->choice
);
2132 else if (!_cups_strcasecmp(choicea
->choice
, choiceb
->choice
))
2134 if (!errors
&& !verbose
)
2135 _cupsLangPuts(stdout
, _(" FAIL"));
2138 _cupsLangPrintf(stdout
,
2139 _(" **FAIL** Option %s choice names %s and "
2140 "%s differ only by case."),
2141 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2148 * Return the number of errors found...
2156 * 'check_defaults()' - Check default option keywords in the PPD file.
2159 static int /* O - Errors found */
2160 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2161 int errors
, /* I - Errors found */
2162 int verbose
, /* I - Verbosity level */
2163 int warn
) /* I - Warnings only? */
2165 int j
, k
; /* Looping vars */
2166 ppd_attr_t
*attr
; /* PPD attribute */
2167 ppd_option_t
*option
; /* Standard UI option */
2168 const char *prefix
; /* WARN/FAIL prefix */
2171 prefix
= warn
? " WARN " : "**FAIL**";
2173 ppdMarkDefaults(ppd
);
2174 if (ppdConflicts(ppd
))
2176 if (!warn
&& !errors
&& !verbose
)
2177 _cupsLangPuts(stdout
, _(" FAIL"));
2180 _cupsLangPrintf(stdout
,
2181 _(" %s Default choices conflicting."), prefix
);
2183 show_conflicts(ppd
, prefix
);
2189 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2191 attr
= ppd
->attrs
[j
];
2193 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2194 !strcmp(attr
->name
, "DefaultFont") ||
2195 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2196 !strcmp(attr
->name
, "DefaultImageableArea") ||
2197 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2198 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2199 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2200 !strcmp(attr
->name
, "DefaultResolution") ||
2201 !strcmp(attr
->name
, "DefaultTransfer"))
2204 if (!strncmp(attr
->name
, "Default", 7))
2206 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2207 strcmp(attr
->value
, "Unknown"))
2210 * Check that the default option value matches a choice...
2213 for (k
= 0; k
< option
->num_choices
; k
++)
2214 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2217 if (k
>= option
->num_choices
)
2219 if (!warn
&& !errors
&& !verbose
)
2220 _cupsLangPuts(stdout
, _(" FAIL"));
2223 _cupsLangPrintf(stdout
,
2224 _(" %s %s %s does not exist."),
2225 prefix
, attr
->name
, attr
->value
);
2239 * 'check_duplex()' - Check duplex keywords in the PPD file.
2242 static int /* O - Errors found */
2243 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2244 int errors
, /* I - Error found */
2245 int verbose
, /* I - Verbosity level */
2246 int warn
) /* I - Warnings only? */
2248 int i
; /* Looping var */
2249 ppd_option_t
*option
; /* PPD option */
2250 ppd_choice_t
*choice
; /* Current choice */
2251 const char *prefix
; /* Message prefix */
2254 prefix
= warn
? " WARN " : "**FAIL**";
2257 * Check for a duplex option, and for standard values...
2260 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2262 if (!ppdFindChoice(option
, "None"))
2266 if (!warn
&& !errors
&& !verbose
)
2267 _cupsLangPuts(stdout
, _(" FAIL"));
2269 _cupsLangPrintf(stdout
,
2270 _(" %s REQUIRED %s does not define "
2272 " REF: Page 122, section 5.17"),
2273 prefix
, option
->keyword
);
2280 for (i
= option
->num_choices
, choice
= option
->choices
;
2283 if (strcmp(choice
->choice
, "None") &&
2284 strcmp(choice
->choice
, "DuplexNoTumble") &&
2285 strcmp(choice
->choice
, "DuplexTumble") &&
2286 strcmp(choice
->choice
, "SimplexTumble"))
2290 if (!warn
&& !errors
&& !verbose
)
2291 _cupsLangPuts(stdout
, _(" FAIL"));
2293 _cupsLangPrintf(stdout
,
2294 _(" %s Bad %s choice %s.\n"
2295 " REF: Page 122, section 5.17"),
2296 prefix
, option
->keyword
, choice
->choice
);
2309 * 'check_filters()' - Check filters in the PPD file.
2312 static int /* O - Errors found */
2313 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2314 const char *root
, /* I - Root directory */
2315 int errors
, /* I - Errors found */
2316 int verbose
, /* I - Verbosity level */
2317 int warn
) /* I - Warnings only? */
2319 ppd_attr_t
*attr
; /* PPD attribute */
2320 const char *ptr
; /* Pointer into string */
2321 char super
[16], /* Super-type for filter */
2322 type
[256], /* Type for filter */
2323 dstsuper
[16], /* Destination super-type for filter */
2324 dsttype
[256], /* Destination type for filter */
2325 program
[1024], /* Program/filter name */
2326 pathprog
[1024]; /* Complete path to program/filter */
2327 int cost
; /* Cost of filter */
2328 const char *prefix
; /* WARN/FAIL prefix */
2329 struct stat fileinfo
; /* File information */
2332 prefix
= warn
? " WARN " : "**FAIL**";
2338 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
2340 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
2342 if (strcmp(attr
->name
, "cupsFilter"))
2344 if (!warn
&& !errors
&& !verbose
)
2345 _cupsLangPuts(stdout
, _(" FAIL"));
2348 _cupsLangPrintf(stdout
,
2349 _(" %s Bad spelling of %s - should be %s."),
2350 prefix
, attr
->name
, "cupsFilter");
2357 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2358 &cost
, program
) != 4)
2360 if (!warn
&& !errors
&& !verbose
)
2361 _cupsLangPuts(stdout
, _(" FAIL"));
2364 _cupsLangPrintf(stdout
,
2365 _(" %s Bad cupsFilter value \"%s\"."),
2366 prefix
, attr
->value
);
2374 if (!strncmp(program
, "maxsize(", 8))
2376 char *mptr
; /* Pointer into maxsize(nnnn) program */
2378 strtoll(program
+ 8, &mptr
, 10);
2382 if (!warn
&& !errors
&& !verbose
)
2383 _cupsLangPuts(stdout
, _(" FAIL"));
2386 _cupsLangPrintf(stdout
,
2387 _(" %s Bad cupsFilter value \"%s\"."),
2388 prefix
, attr
->value
);
2397 while (_cups_isspace(*mptr
))
2400 _cups_strcpy(program
, mptr
);
2403 if (strcmp(program
, "-"))
2405 if (program
[0] == '/')
2406 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2409 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2410 ptr
= CUPS_SERVERBIN
;
2412 if (*ptr
== '/' || !*root
)
2413 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2416 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2420 if (stat(pathprog
, &fileinfo
))
2422 if (!warn
&& !errors
&& !verbose
)
2423 _cupsLangPuts(stdout
, _(" FAIL"));
2426 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2427 prefix
, "cupsFilter", pathprog
);
2432 else if (fileinfo
.st_uid
!= 0 ||
2433 (fileinfo
.st_mode
& MODE_WRITE
) ||
2434 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2436 if (!warn
&& !errors
&& !verbose
)
2437 _cupsLangPuts(stdout
, _(" FAIL"));
2440 _cupsLangPrintf(stdout
,
2441 _(" %s Bad permissions on %s file \"%s\"."),
2442 prefix
, "cupsFilter", pathprog
);
2448 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2456 for (attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
);
2458 attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
))
2460 if (strcmp(attr
->name
, "cupsFilter2"))
2462 if (!warn
&& !errors
&& !verbose
)
2463 _cupsLangPuts(stdout
, _(" FAIL"));
2466 _cupsLangPrintf(stdout
,
2467 _(" %s Bad spelling of %s - should be %s."),
2468 prefix
, attr
->name
, "cupsFilter2");
2475 sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
2476 super
, type
, dstsuper
, dsttype
, &cost
, program
) != 6)
2478 if (!warn
&& !errors
&& !verbose
)
2479 _cupsLangPuts(stdout
, _(" FAIL"));
2482 _cupsLangPrintf(stdout
,
2483 _(" %s Bad cupsFilter2 value \"%s\"."),
2484 prefix
, attr
->value
);
2492 if (!strncmp(program
, "maxsize(", 8))
2494 char *mptr
; /* Pointer into maxsize(nnnn) program */
2496 strtoll(program
+ 8, &mptr
, 10);
2500 if (!warn
&& !errors
&& !verbose
)
2501 _cupsLangPuts(stdout
, _(" FAIL"));
2504 _cupsLangPrintf(stdout
,
2505 _(" %s Bad cupsFilter2 value \"%s\"."),
2506 prefix
, attr
->value
);
2515 while (_cups_isspace(*mptr
))
2518 _cups_strcpy(program
, mptr
);
2521 if (strcmp(program
, "-"))
2523 if (strncmp(program
, "maxsize(", 8) &&
2524 (ptr
= strchr(program
+ 8, ')')) != NULL
)
2527 while (_cups_isspace(*ptr
))
2530 _cups_strcpy(program
, ptr
);
2533 if (program
[0] == '/')
2534 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2537 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2538 ptr
= CUPS_SERVERBIN
;
2540 if (*ptr
== '/' || !*root
)
2541 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2544 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2548 if (stat(pathprog
, &fileinfo
))
2550 if (!warn
&& !errors
&& !verbose
)
2551 _cupsLangPuts(stdout
, _(" FAIL"));
2554 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2555 prefix
, "cupsFilter2", pathprog
);
2560 else if (fileinfo
.st_uid
!= 0 ||
2561 (fileinfo
.st_mode
& MODE_WRITE
) ||
2562 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2564 if (!warn
&& !errors
&& !verbose
)
2565 _cupsLangPuts(stdout
, _(" FAIL"));
2568 _cupsLangPrintf(stdout
,
2569 _(" %s Bad permissions on %s file \"%s\"."),
2570 prefix
, "cupsFilter2", pathprog
);
2576 errors
= valid_path("cupsFilter2", pathprog
, errors
, verbose
, warn
);
2584 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2586 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2588 if (strcmp(attr
->name
, "cupsPreFilter"))
2590 if (!warn
&& !errors
&& !verbose
)
2591 _cupsLangPuts(stdout
, _(" FAIL"));
2594 _cupsLangPrintf(stdout
,
2595 _(" %s Bad spelling of %s - should be %s."),
2596 prefix
, attr
->name
, "cupsPreFilter");
2603 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2604 &cost
, program
) != 4)
2606 if (!warn
&& !errors
&& !verbose
)
2607 _cupsLangPuts(stdout
, _(" FAIL"));
2610 _cupsLangPrintf(stdout
,
2611 _(" %s Bad cupsPreFilter value \"%s\"."),
2612 prefix
, attr
->value
? attr
->value
: "");
2617 else if (strcmp(program
, "-"))
2619 if (program
[0] == '/')
2620 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2623 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2624 ptr
= CUPS_SERVERBIN
;
2626 if (*ptr
== '/' || !*root
)
2627 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2630 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2634 if (stat(pathprog
, &fileinfo
))
2636 if (!warn
&& !errors
&& !verbose
)
2637 _cupsLangPuts(stdout
, _(" FAIL"));
2640 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2641 prefix
, "cupsPreFilter", pathprog
);
2646 else if (fileinfo
.st_uid
!= 0 ||
2647 (fileinfo
.st_mode
& MODE_WRITE
) ||
2648 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2650 if (!warn
&& !errors
&& !verbose
)
2651 _cupsLangPuts(stdout
, _(" FAIL"));
2654 _cupsLangPrintf(stdout
,
2655 _(" %s Bad permissions on %s file \"%s\"."),
2656 prefix
, "cupsPreFilter", pathprog
);
2662 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2671 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2673 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2675 if (strcmp(attr
->name
, "APDialogExtension"))
2677 if (!warn
&& !errors
&& !verbose
)
2678 _cupsLangPuts(stdout
, _(" FAIL"));
2681 _cupsLangPrintf(stdout
,
2682 _(" %s Bad spelling of %s - should be %s."),
2683 prefix
, attr
->name
, "APDialogExtension");
2689 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2690 attr
->value
? attr
->value
: "(null)");
2692 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2694 if (!warn
&& !errors
&& !verbose
)
2695 _cupsLangPuts(stdout
, _(" FAIL"));
2698 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2699 prefix
, "APDialogExtension", pathprog
);
2704 else if (fileinfo
.st_uid
!= 0 ||
2705 (fileinfo
.st_mode
& MODE_WRITE
) ||
2706 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2708 if (!warn
&& !errors
&& !verbose
)
2709 _cupsLangPuts(stdout
, _(" FAIL"));
2712 _cupsLangPrintf(stdout
,
2713 _(" %s Bad permissions on %s file \"%s\"."),
2714 prefix
, "APDialogExtension", pathprog
);
2720 errors
= valid_path("APDialogExtension", pathprog
, errors
, verbose
,
2728 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2730 if (strcmp(attr
->name
, "APPrinterIconPath"))
2732 if (!warn
&& !errors
&& !verbose
)
2733 _cupsLangPuts(stdout
, _(" FAIL"));
2736 _cupsLangPrintf(stdout
,
2737 _(" %s Bad spelling of %s - should be %s."),
2738 prefix
, attr
->name
, "APPrinterIconPath");
2744 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2745 attr
->value
? attr
->value
: "(null)");
2747 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2749 if (!warn
&& !errors
&& !verbose
)
2750 _cupsLangPuts(stdout
, _(" FAIL"));
2753 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2754 prefix
, "APPrinterIconPath", pathprog
);
2759 else if (fileinfo
.st_uid
!= 0 ||
2760 (fileinfo
.st_mode
& MODE_WRITE
) ||
2761 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2763 if (!warn
&& !errors
&& !verbose
)
2764 _cupsLangPuts(stdout
, _(" FAIL"));
2767 _cupsLangPrintf(stdout
,
2768 _(" %s Bad permissions on %s file \"%s\"."),
2769 prefix
, "APPrinterIconPath", pathprog
);
2775 errors
= valid_path("APPrinterIconPath", pathprog
, errors
, verbose
,
2780 * APPrinterLowInkTool
2783 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2785 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2787 if (!warn
&& !errors
&& !verbose
)
2788 _cupsLangPuts(stdout
, _(" FAIL"));
2791 _cupsLangPrintf(stdout
,
2792 _(" %s Bad spelling of %s - should be %s."),
2793 prefix
, attr
->name
, "APPrinterLowInkTool");
2799 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2800 attr
->value
? attr
->value
: "(null)");
2802 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2804 if (!warn
&& !errors
&& !verbose
)
2805 _cupsLangPuts(stdout
, _(" FAIL"));
2808 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2809 prefix
, "APPrinterLowInkTool", pathprog
);
2814 else if (fileinfo
.st_uid
!= 0 ||
2815 (fileinfo
.st_mode
& MODE_WRITE
) ||
2816 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2818 if (!warn
&& !errors
&& !verbose
)
2819 _cupsLangPuts(stdout
, _(" FAIL"));
2822 _cupsLangPrintf(stdout
,
2823 _(" %s Bad permissions on %s file \"%s\"."),
2824 prefix
, "APPrinterLowInkTool", pathprog
);
2830 errors
= valid_path("APPrinterLowInkTool", pathprog
, errors
, verbose
,
2835 * APPrinterUtilityPath
2838 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2840 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2842 if (!warn
&& !errors
&& !verbose
)
2843 _cupsLangPuts(stdout
, _(" FAIL"));
2846 _cupsLangPrintf(stdout
,
2847 _(" %s Bad spelling of %s - should be %s."),
2848 prefix
, attr
->name
, "APPrinterUtilityPath");
2854 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2855 attr
->value
? attr
->value
: "(null)");
2857 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2859 if (!warn
&& !errors
&& !verbose
)
2860 _cupsLangPuts(stdout
, _(" FAIL"));
2863 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2864 prefix
, "APPrinterUtilityPath", pathprog
);
2869 else if (fileinfo
.st_uid
!= 0 ||
2870 (fileinfo
.st_mode
& MODE_WRITE
) ||
2871 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2873 if (!warn
&& !errors
&& !verbose
)
2874 _cupsLangPuts(stdout
, _(" FAIL"));
2877 _cupsLangPrintf(stdout
,
2878 _(" %s Bad permissions on %s file \"%s\"."),
2879 prefix
, "APPrinterUtilityPath", pathprog
);
2885 errors
= valid_path("APPrinterUtilityPath", pathprog
, errors
, verbose
,
2890 * APScanAppBundleID and APScanAppPath
2893 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2895 if (strcmp(attr
->name
, "APScanAppPath"))
2897 if (!warn
&& !errors
&& !verbose
)
2898 _cupsLangPuts(stdout
, _(" FAIL"));
2901 _cupsLangPrintf(stdout
,
2902 _(" %s Bad spelling of %s - should be %s."),
2903 prefix
, attr
->name
, "APScanAppPath");
2909 if (!attr
->value
|| stat(attr
->value
, &fileinfo
))
2911 if (!warn
&& !errors
&& !verbose
)
2912 _cupsLangPuts(stdout
, _(" FAIL"));
2915 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2916 prefix
, "APScanAppPath",
2917 attr
->value
? attr
->value
: "<NULL>");
2922 else if (fileinfo
.st_uid
!= 0 ||
2923 (fileinfo
.st_mode
& MODE_WRITE
) ||
2924 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2926 if (!warn
&& !errors
&& !verbose
)
2927 _cupsLangPuts(stdout
, _(" FAIL"));
2930 _cupsLangPrintf(stdout
,
2931 _(" %s Bad permissions on %s file \"%s\"."),
2932 prefix
, "APScanAppPath", attr
->value
);
2938 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2941 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2943 if (!warn
&& !errors
&& !verbose
)
2944 _cupsLangPuts(stdout
, _(" FAIL"));
2947 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2948 "APScanAppPath and APScanAppBundleID."),
2955 #endif /* __APPLE__ */
2962 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2965 static int /* O - Errors found */
2966 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2967 const char *root
, /* I - Root directory */
2968 int errors
, /* I - Errors found */
2969 int verbose
, /* I - Verbosity level */
2970 int warn
) /* I - Warnings only? */
2972 int i
; /* Looping var */
2973 ppd_attr_t
*attr
; /* PPD attribute */
2974 const char *ptr
; /* Pointer into string */
2975 const char *prefix
; /* WARN/FAIL prefix */
2976 char filename
[1024]; /* Profile filename */
2977 struct stat fileinfo
; /* File information */
2978 int num_profiles
= 0; /* Number of profiles */
2979 unsigned hash
, /* Current hash value */
2980 hashes
[1000]; /* Hash values of profile names */
2981 const char *specs
[1000]; /* Specifiers for profiles */
2984 prefix
= warn
? " WARN " : "**FAIL**";
2986 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
2988 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
2991 * Check for valid selector...
2994 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
2997 if (!attr
->value
|| i
< 2)
2999 if (!warn
&& !errors
&& !verbose
)
3000 _cupsLangPuts(stdout
, _(" FAIL"));
3003 _cupsLangPrintf(stdout
,
3004 _(" %s Bad cupsICCProfile %s."),
3005 prefix
, attr
->spec
);
3014 * Check for valid profile filename...
3017 if (attr
->value
[0] == '/')
3018 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
3021 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
3024 if (*ptr
== '/' || !*root
)
3025 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
3028 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
3032 if (stat(filename
, &fileinfo
))
3034 if (!warn
&& !errors
&& !verbose
)
3035 _cupsLangPuts(stdout
, _(" FAIL"));
3038 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
3039 prefix
, "cupsICCProfile", filename
);
3044 else if (fileinfo
.st_uid
!= 0 ||
3045 (fileinfo
.st_mode
& MODE_WRITE
) ||
3046 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
3048 if (!warn
&& !errors
&& !verbose
)
3049 _cupsLangPuts(stdout
, _(" FAIL"));
3052 _cupsLangPrintf(stdout
,
3053 _(" %s Bad permissions on %s file \"%s\"."),
3054 prefix
, "cupsICCProfile", filename
);
3060 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
3063 * Check for hash collisions...
3066 hash
= _ppdHashName(attr
->spec
);
3068 if (num_profiles
> 0)
3070 for (i
= 0; i
< num_profiles
; i
++)
3071 if (hashes
[i
] == hash
)
3074 if (i
< num_profiles
)
3076 if (!warn
&& !errors
&& !verbose
)
3077 _cupsLangPuts(stdout
, _(" FAIL"));
3080 _cupsLangPrintf(stdout
,
3081 _(" %s cupsICCProfile %s hash value "
3082 "collides with %s."), prefix
, attr
->spec
,
3091 * Remember up to 1000 profiles...
3094 if (num_profiles
< 1000)
3096 hashes
[num_profiles
] = hash
;
3097 specs
[num_profiles
] = attr
->spec
;
3107 * 'check_sizes()' - Check media sizes in the PPD file.
3110 static int /* O - Errors found */
3111 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
3112 int errors
, /* I - Errors found */
3113 int verbose
, /* I - Verbosity level */
3114 int warn
) /* I - Warnings only? */
3116 int i
; /* Looping var */
3117 ppd_size_t
*size
; /* Current size */
3118 int width
, /* Custom width */
3119 length
; /* Custom length */
3120 const char *prefix
; /* WARN/FAIL prefix */
3121 ppd_option_t
*page_size
, /* PageSize option */
3122 *page_region
; /* PageRegion option */
3123 pwg_media_t
*pwg_media
; /* PWG media */
3124 char buf
[PPD_MAX_NAME
]; /* PapeSize name that is supposed to be */
3125 const char *ptr
; /* Pointer into string */
3126 int width_2540ths
, /* PageSize width in 2540ths */
3127 length_2540ths
; /* PageSize length in 2540ths */
3128 int is_ok
; /* Flag for PageSize name verification */
3129 double width_tmp
, /* Width after rounded up */
3130 length_tmp
, /* Length after rounded up */
3131 width_inch
, /* Width in inches */
3132 length_inch
, /* Length in inches */
3133 width_mm
, /* Width in millimeters */
3134 length_mm
; /* Length in millimeters */
3137 prefix
= warn
? " WARN " : "**FAIL**";
3139 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
3141 if (!warn
&& !errors
&& !verbose
)
3142 _cupsLangPuts(stdout
, _(" FAIL"));
3145 _cupsLangPrintf(stdout
,
3146 _(" %s Missing REQUIRED PageSize option.\n"
3147 " REF: Page 99, section 5.14."),
3154 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
3156 if (!warn
&& !errors
&& !verbose
)
3157 _cupsLangPuts(stdout
, _(" FAIL"));
3160 _cupsLangPrintf(stdout
,
3161 _(" %s Missing REQUIRED PageRegion option.\n"
3162 " REF: Page 100, section 5.14."),
3169 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
3172 * Check that the size name is standard...
3175 if (!strcmp(size
->name
, "Custom"))
3178 * Skip custom page size...
3184 if (warn
!= 2 && size
->name
[0] == 'w' &&
3185 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
3188 * Validate device-specific size wNNNhNNN should have proper width and
3192 if (fabs(width
- size
->width
) >= 1.0 ||
3193 fabs(length
- size
->length
) >= 1.0)
3195 if (!warn
&& !errors
&& !verbose
)
3196 _cupsLangPuts(stdout
, _(" FAIL"));
3199 _cupsLangPrintf(stdout
,
3200 _(" %s Size \"%s\" has unexpected dimensions "
3202 prefix
, size
->name
, size
->width
, size
->length
);
3210 * Verify that the size is defined for both PageSize and PageRegion...
3213 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
3215 if (!warn
&& !errors
&& !verbose
)
3216 _cupsLangPuts(stdout
, _(" FAIL"));
3219 _cupsLangPrintf(stdout
,
3220 _(" %s Size \"%s\" defined for %s but not for "
3222 prefix
, size
->name
, "PageRegion", "PageSize");
3227 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3229 if (!warn
&& !errors
&& !verbose
)
3230 _cupsLangPuts(stdout
, _(" FAIL"));
3233 _cupsLangPrintf(stdout
,
3234 _(" %s Size \"%s\" defined for %s but not for "
3236 prefix
, size
->name
, "PageSize", "PageRegion");
3243 * Verify that the size name is Adobe standard name if it's a standard size
3244 * and the dimentional name if it's not a standard size. Suffix should be
3245 * .Fullbleed, etc., or numeric, e.g., Letter, Letter.Fullbleed,
3246 * Letter.Transverse, Letter1, Letter2, 4x8, 55x91mm, 55x91mm.Fullbleed, etc.
3252 width_2540ths
= (size
->length
> size
->width
) ?
3253 PWG_FROM_POINTS(size
->width
) :
3254 PWG_FROM_POINTS(size
->length
);
3255 length_2540ths
= (size
->length
> size
->width
) ?
3256 PWG_FROM_POINTS(size
->length
) :
3257 PWG_FROM_POINTS(size
->width
);
3258 pwg_media
= pwgMediaForSize(width_2540ths
, length_2540ths
);
3261 (abs(pwg_media
->width
- width_2540ths
) > 34 ||
3262 abs(pwg_media
->length
- length_2540ths
) > 34))
3263 pwg_media
= NULL
; /* Only flag matches within a point */
3265 if (pwg_media
&& pwg_media
->ppd
&&
3266 (pwg_media
->ppd
[0] < 'a' || pwg_media
->ppd
[0] > 'z'))
3268 size_t ppdlen
= strlen(pwg_media
->ppd
);
3269 /* Length of standard PPD name */
3271 strlcpy(buf
, pwg_media
->ppd
, sizeof(buf
));
3273 if (strcmp(size
->name
, buf
) && size
->width
> size
->length
)
3275 if (!strcmp(pwg_media
->ppd
, "DoublePostcardRotated"))
3276 strlcpy(buf
, "DoublePostcard", sizeof(buf
));
3277 else if (strstr(size
->name
, ".Transverse"))
3278 snprintf(buf
, sizeof(buf
), "%s.Transverse", pwg_media
->ppd
);
3280 snprintf(buf
, sizeof(buf
), "%sRotated", pwg_media
->ppd
);
3282 ppdlen
= strlen(buf
);
3285 if (size
->left
== 0 && size
->bottom
== 0 &&
3286 size
->right
== size
->width
&& size
->top
== size
->length
)
3288 strlcat(buf
, ".Fullbleed", sizeof(buf
) - strlen(buf
));
3289 if (_cups_strcasecmp(size
->name
, buf
))
3292 * Allow an additional qualifier such as ".WithTab"...
3295 size_t buflen
= strlen(buf
);/* Length of full bleed name */
3297 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3298 size
->name
[buflen
] != '.')
3302 else if (!strncmp(size
->name
, pwg_media
->ppd
, ppdlen
))
3305 * Check for a proper qualifier (number, "Small", or .something)...
3308 ptr
= size
->name
+ ppdlen
;
3310 if (isdigit(*ptr
& 255))
3312 for (ptr
++; *ptr
; ptr
++)
3314 if (!isdigit(*ptr
& 255))
3321 else if (*ptr
!= '.' && *ptr
&& strcmp(ptr
, "Small"))
3327 * Check for EnvSizeName as well...
3330 if (strncmp(pwg_media
->ppd
, "Env", 3) &&
3331 !strncmp(size
->name
, "Env", 3))
3332 snprintf(buf
, sizeof(buf
), "Env%s", pwg_media
->ppd
);
3334 if (strcmp(size
->name
, buf
))
3339 _cupsLangPrintf(stdout
,
3340 _(" %s Size \"%s\" should be the Adobe "
3341 "standard name \"%s\"."),
3342 prefix
, size
->name
, buf
);
3346 width_tmp
= (fabs(size
->width
- ceil(size
->width
)) < 0.1) ?
3347 ceil(size
->width
) : size
->width
;
3348 length_tmp
= (fabs(size
->length
- ceil(size
->length
)) < 0.1) ?
3349 ceil(size
->length
) : size
->length
;
3351 if (fmod(width_tmp
, 9.0) == 0.0 && fmod(length_tmp
, 9.0) == 0.0)
3353 width_inch
= width_tmp
/ 72.0;
3354 length_inch
= length_tmp
/ 72.0;
3356 snprintf(buf
, sizeof(buf
), "%gx%g", width_inch
, length_inch
);
3360 width_mm
= size
->width
/ 72.0 * 25.4;
3361 length_mm
= size
->length
/ 72.0 * 25.4;
3363 snprintf(buf
, sizeof(buf
), "%.0fx%.0fmm", width_mm
, length_mm
);
3366 if (size
->left
== 0 && size
->bottom
== 0 &&
3367 size
->right
== size
->width
&& size
->top
== size
->length
)
3368 strlcat(buf
, ".Fullbleed", sizeof(buf
));
3369 else if (size
->width
> size
->length
)
3370 strlcat(buf
, ".Transverse", sizeof(buf
));
3372 if (_cups_strcasecmp(size
->name
, buf
))
3374 size_t buflen
= strlen(buf
);
3375 /* Length of proposed name */
3377 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3378 (strcmp(size
->name
+ buflen
, "in") &&
3379 size
->name
[buflen
] != '.'))
3381 char altbuf
[PPD_MAX_NAME
];
3382 /* Alternate "wNNNhNNN" name */
3383 size_t altlen
; /* Length of alternate name */
3385 snprintf(altbuf
, sizeof(altbuf
), "w%.0fh%.0f", size
->width
,
3387 altlen
= strlen(altbuf
);
3388 if (_cups_strncasecmp(size
->name
, altbuf
, altlen
) ||
3389 (size
->name
[altlen
] && size
->name
[altlen
] != '.'))
3390 _cupsLangPrintf(stdout
,
3391 _(" %s Size \"%s\" should be \"%s\"."),
3392 prefix
, size
->name
, buf
);
3404 * 'check_translations()' - Check translations in the PPD file.
3407 static int /* O - Errors found */
3408 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3409 int errors
, /* I - Errors found */
3410 int verbose
, /* I - Verbosity level */
3411 int warn
) /* I - Warnings only? */
3413 int j
; /* Looping var */
3414 ppd_attr_t
*attr
; /* PPD attribute */
3415 cups_array_t
*languages
; /* Array of languages */
3416 int langlen
; /* Length of language */
3417 char *language
, /* Current language */
3418 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3419 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3420 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3421 cllkeyword
[PPD_MAX_NAME
];
3422 /* Custom option keyword (base) */
3423 ppd_option_t
*option
; /* Standard UI option */
3424 ppd_coption_t
*coption
; /* Custom option */
3425 ppd_cparam_t
*cparam
; /* Custom parameter */
3426 char ll
[3]; /* Base language */
3427 const char *prefix
; /* WARN/FAIL prefix */
3428 const char *text
; /* Pointer into UI text */
3431 prefix
= warn
? " WARN " : "**FAIL**";
3433 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3436 * This file contains localizations, check them...
3439 for (language
= (char *)cupsArrayFirst(languages
);
3441 language
= (char *)cupsArrayNext(languages
))
3443 langlen
= (int)strlen(language
);
3444 if (langlen
!= 2 && langlen
!= 5)
3446 if (!warn
&& !errors
&& !verbose
)
3447 _cupsLangPuts(stdout
, _(" FAIL"));
3450 _cupsLangPrintf(stdout
,
3451 _(" %s Bad language \"%s\"."),
3460 if (!strcmp(language
, "en"))
3463 strlcpy(ll
, language
, sizeof(ll
));
3466 * Loop through all options and choices...
3469 for (option
= ppdFirstOption(ppd
);
3471 option
= ppdNextOption(ppd
))
3473 if (!strcmp(option
->keyword
, "PageRegion"))
3476 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3477 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3479 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3480 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3482 if (!warn
&& !errors
&& !verbose
)
3483 _cupsLangPuts(stdout
, _(" FAIL"));
3486 _cupsLangPrintf(stdout
,
3487 _(" %s Missing \"%s\" translation "
3488 "string for option %s."),
3489 prefix
, language
, option
->keyword
);
3494 else if (!valid_utf8(attr
->text
))
3496 if (!warn
&& !errors
&& !verbose
)
3497 _cupsLangPuts(stdout
, _(" FAIL"));
3500 _cupsLangPrintf(stdout
,
3501 _(" %s Bad UTF-8 \"%s\" translation "
3502 "string for option %s."),
3503 prefix
, language
, option
->keyword
);
3509 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3511 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3514 for (j
= 0; j
< option
->num_choices
; j
++)
3517 * First see if this choice is a number; if so, don't require
3521 for (text
= option
->choices
[j
].text
; *text
; text
++)
3522 if (!strchr("0123456789-+.", *text
))
3529 * Check custom choices differently...
3532 if (!_cups_strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3533 (coption
= ppdFindCustomOption(ppd
,
3534 option
->keyword
)) != NULL
)
3536 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3537 language
, option
->keyword
);
3539 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3540 !valid_utf8(attr
->text
))
3542 if (!warn
&& !errors
&& !verbose
)
3543 _cupsLangPuts(stdout
, _(" FAIL"));
3546 _cupsLangPrintf(stdout
,
3547 _(" %s Bad UTF-8 \"%s\" "
3548 "translation string for option %s, "
3551 ckeyword
+ 1 + strlen(language
),
3558 if (_cups_strcasecmp(option
->keyword
, "PageSize"))
3560 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3562 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3564 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3565 language
, option
->keyword
);
3566 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3567 ll
, option
->keyword
);
3569 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3570 cparam
->name
)) == NULL
&&
3571 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3572 cparam
->name
)) == NULL
)
3574 if (!warn
&& !errors
&& !verbose
)
3575 _cupsLangPuts(stdout
, _(" FAIL"));
3578 _cupsLangPrintf(stdout
,
3579 _(" %s Missing \"%s\" "
3580 "translation string for option %s, "
3583 ckeyword
+ 1 + strlen(language
),
3589 else if (!valid_utf8(attr
->text
))
3591 if (!warn
&& !errors
&& !verbose
)
3592 _cupsLangPuts(stdout
, _(" FAIL"));
3595 _cupsLangPrintf(stdout
,
3596 _(" %s Bad UTF-8 \"%s\" "
3597 "translation string for option %s, "
3600 ckeyword
+ 1 + strlen(language
),
3609 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3610 option
->choices
[j
].choice
)) == NULL
&&
3611 (attr
= ppdFindAttr(ppd
, llkeyword
,
3612 option
->choices
[j
].choice
)) == NULL
)
3614 if (!warn
&& !errors
&& !verbose
)
3615 _cupsLangPuts(stdout
, _(" FAIL"));
3618 _cupsLangPrintf(stdout
,
3619 _(" %s Missing \"%s\" "
3620 "translation string for option %s, "
3622 prefix
, language
, option
->keyword
,
3623 option
->choices
[j
].choice
);
3628 else if (!valid_utf8(attr
->text
))
3630 if (!warn
&& !errors
&& !verbose
)
3631 _cupsLangPuts(stdout
, _(" FAIL"));
3634 _cupsLangPrintf(stdout
,
3635 _(" %s Bad UTF-8 \"%s\" "
3636 "translation string for option %s, "
3638 prefix
, language
, option
->keyword
,
3639 option
->choices
[j
].choice
);
3649 * Verify that we have the base language for each localized one...
3652 for (language
= (char *)cupsArrayFirst(languages
);
3654 language
= (char *)cupsArrayNext(languages
))
3658 * Lookup the base language...
3661 cupsArraySave(languages
);
3663 strlcpy(ll
, language
, sizeof(ll
));
3665 if (!cupsArrayFind(languages
, ll
) &&
3666 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3668 if (!warn
&& !errors
&& !verbose
)
3669 _cupsLangPuts(stdout
, _(" FAIL"));
3672 _cupsLangPrintf(stdout
,
3673 _(" %s No base translation \"%s\" "
3674 "is included in file."), prefix
, ll
);
3680 cupsArrayRestore(languages
);
3684 * Free memory used for the languages...
3687 _ppdFreeLanguages(languages
);
3695 * 'show_conflicts()' - Show option conflicts in a PPD file.
3699 show_conflicts(ppd_file_t
*ppd
, /* I - PPD to check */
3700 const char *prefix
) /* I - Prefix string */
3702 int i
, j
; /* Looping variables */
3703 ppd_const_t
*c
; /* Current constraint */
3704 ppd_option_t
*o1
, *o2
; /* Options */
3705 ppd_choice_t
*c1
, *c2
; /* Choices */
3709 * Loop through all of the UI constraints and report any options
3713 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3716 * Grab pointers to the first option...
3719 o1
= ppdFindOption(ppd
, c
->option1
);
3723 else if (c
->choice1
[0] != '\0')
3726 * This constraint maps to a specific choice.
3729 c1
= ppdFindChoice(o1
, c
->choice1
);
3734 * This constraint applies to any choice for this option.
3737 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3742 !_cups_strcasecmp(c1
->choice
, "None") ||
3743 !_cups_strcasecmp(c1
->choice
, "Off") ||
3744 !_cups_strcasecmp(c1
->choice
, "False"))
3749 * Grab pointers to the second option...
3752 o2
= ppdFindOption(ppd
, c
->option2
);
3756 else if (c
->choice2
[0] != '\0')
3759 * This constraint maps to a specific choice.
3762 c2
= ppdFindChoice(o2
, c
->choice2
);
3767 * This constraint applies to any choice for this option.
3770 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3775 !_cups_strcasecmp(c2
->choice
, "None") ||
3776 !_cups_strcasecmp(c2
->choice
, "Off") ||
3777 !_cups_strcasecmp(c2
->choice
, "False"))
3782 * If both options are marked then there is a conflict...
3785 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3786 _cupsLangPrintf(stdout
,
3787 _(" %s \"%s %s\" conflicts with \"%s %s\"\n"
3788 " (constraint=\"%s %s %s %s\")."),
3789 prefix
, o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3790 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3796 * 'test_raster()' - Test PostScript commands for raster printers.
3799 static int /* O - 1 on success, 0 on failure */
3800 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3801 int verbose
) /* I - Verbosity */
3803 cups_page_header2_t header
; /* Page header */
3806 ppdMarkDefaults(ppd
);
3807 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3810 _cupsLangPuts(stdout
, _(" FAIL"));
3813 _cupsLangPrintf(stdout
,
3814 _(" **FAIL** Default option code cannot be "
3815 "interpreted: %s"), cupsRasterErrorString());
3821 * Try a test of custom page size code, if available...
3824 if (!ppdPageSize(ppd
, "Custom.612x792"))
3827 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3829 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3832 _cupsLangPuts(stdout
, _(" FAIL"));
3835 _cupsLangPrintf(stdout
,
3836 _(" **FAIL** Default option code cannot be "
3837 "interpreted: %s"), cupsRasterErrorString());
3847 * 'usage()' - Show program usage.
3853 _cupsLangPuts(stdout
, _("Warning: This program will be removed in a future version of CUPS."));
3854 _cupsLangPuts(stdout
, _("Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
3855 " program | cupstestppd [options] -"));
3856 _cupsLangPuts(stdout
, _("Options:"));
3857 _cupsLangPuts(stdout
, _("-I {filename,filters,none,profiles}\n"
3858 " Ignore specific warnings"));
3859 _cupsLangPuts(stdout
, _("-R root-directory Set alternate root"));
3860 _cupsLangPuts(stdout
, _("-W {all,none,constraints,defaults,duplex,filters,profiles,sizes,translations}\n"
3861 " Issue warnings instead of errors"));
3862 _cupsLangPuts(stdout
, _("-q Run silently"));
3863 _cupsLangPuts(stdout
, _("-r Use 'relaxed' open mode"));
3864 _cupsLangPuts(stdout
, _("-v Be verbose"));
3865 _cupsLangPuts(stdout
, _("-vv Be very verbose"));
3872 * 'valid_path()' - Check whether a path has the correct capitalization.
3875 static int /* O - Errors found */
3876 valid_path(const char *keyword
, /* I - Keyword using path */
3877 const char *path
, /* I - Path to check */
3878 int errors
, /* I - Errors found */
3879 int verbose
, /* I - Verbosity level */
3880 int warn
) /* I - Warnings only? */
3882 cups_dir_t
*dir
; /* Current directory */
3883 cups_dentry_t
*dentry
; /* Current directory entry */
3884 char temp
[1024], /* Temporary path */
3885 *ptr
; /* Pointer into temporary path */
3886 const char *prefix
; /* WARN/FAIL prefix */
3889 prefix
= warn
? " WARN " : "**FAIL**";
3892 * Loop over the components of the path, checking that the entry exists with
3893 * the same capitalization...
3896 strlcpy(temp
, path
, sizeof(temp
));
3898 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3901 * Chop off the trailing component so temp == dirname and ptr == basename.
3907 * Try opening the directory containing the base name...
3911 dir
= cupsDirOpen(temp
);
3913 dir
= cupsDirOpen("/");
3919 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3921 if (!strcmp(dentry
->filename
, ptr
))
3929 * Display an error if the filename doesn't exist with the same
3935 if (!warn
&& !errors
&& !verbose
)
3936 _cupsLangPuts(stdout
, _(" FAIL"));
3939 _cupsLangPrintf(stdout
,
3940 _(" %s %s file \"%s\" has the wrong "
3941 "capitalization."), prefix
, keyword
, path
);
3955 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3958 static int /* O - 1 if valid, 0 if not */
3959 valid_utf8(const char *s
) /* I - String to check */
3966 * Check for valid UTF-8 sequence...
3969 if ((*s
& 0xc0) == 0x80)
3970 return (0); /* Illegal suffix byte */
3971 else if ((*s
& 0xe0) == 0xc0)
3974 * 2-byte sequence...
3979 if ((*s
& 0xc0) != 0x80)
3980 return (0); /* Missing suffix byte */
3982 else if ((*s
& 0xf0) == 0xe0)
3985 * 3-byte sequence...
3990 if ((*s
& 0xc0) != 0x80)
3991 return (0); /* Missing suffix byte */
3995 if ((*s
& 0xc0) != 0x80)
3996 return (0); /* Missing suffix byte */
3998 else if ((*s
& 0xf8) == 0xf0)
4001 * 4-byte sequence...
4006 if ((*s
& 0xc0) != 0x80)
4007 return (0); /* Missing suffix byte */
4011 if ((*s
& 0xc0) != 0x80)
4012 return (0); /* Missing suffix byte */
4016 if ((*s
& 0xc0) != 0x80)
4017 return (0); /* Missing suffix byte */
4020 return (0); /* Bad sequence */