4 * PPD test program for CUPS.
6 * Copyright 2007-2015 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 * Include necessary headers...
24 #include <cups/cups-private.h>
26 #include <cups/ppd-private.h>
27 #include <cups/raster.h>
35 * Error warning overrides...
45 WARN_TRANSLATIONS
= 16,
84 #define MODE_WRITE 0022 /* Group/other write */
85 #define MODE_MASK 0555 /* Owner/group/other read+exec/search */
86 #define MODE_DATAFILE 0444 /* Owner/group/other read */
87 #define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
88 #define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
95 static void check_basics(const char *filename
);
96 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
98 static int check_case(ppd_file_t
*ppd
, int errors
, int verbose
);
99 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
101 static int check_duplex(ppd_file_t
*ppd
, int errors
, int verbose
,
103 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
104 int verbose
, int warn
);
105 static int check_profiles(ppd_file_t
*ppd
, const char *root
, int errors
,
106 int verbose
, int warn
);
107 static int check_sizes(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
108 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,
110 static void show_conflicts(ppd_file_t
*ppd
, const char *prefix
);
111 static int test_raster(ppd_file_t
*ppd
, int verbose
);
112 static void usage(void) __attribute__((noreturn
));
113 static int valid_path(const char *keyword
, const char *path
, int errors
,
114 int verbose
, int warn
);
115 static int valid_utf8(const char *s
);
119 * 'main()' - Main entry for test program.
122 int /* O - Exit status */
123 main(int argc
, /* I - Number of command-line args */
124 char *argv
[]) /* I - Command-line arguments */
126 int i
, j
, k
, m
, n
; /* Looping vars */
127 size_t len
; /* Length of option name */
128 char *opt
; /* Option character */
129 const char *ptr
; /* Pointer into string */
130 cups_file_t
*fp
; /* PPD file */
131 int files
; /* Number of files */
132 int verbose
; /* Want verbose output? */
133 int warn
; /* Which errors to just warn about */
134 int ignore
; /* Which errors to ignore */
135 int status
; /* Exit status */
136 int errors
; /* Number of conformance errors */
137 int ppdversion
; /* PPD spec version in PPD file */
138 ppd_status_t error
; /* Status of ppdOpen*() */
139 int line
; /* Line number for error */
140 char *root
; /* Root directory */
141 int xdpi
, /* X resolution */
142 ydpi
; /* Y resolution */
143 ppd_file_t
*ppd
; /* PPD file record */
144 ppd_attr_t
*attr
; /* PPD attribute */
145 ppd_size_t
*size
; /* Size record */
146 ppd_group_t
*group
; /* UI group */
147 ppd_option_t
*option
; /* Standard UI option */
148 ppd_group_t
*group2
; /* UI group */
149 ppd_option_t
*option2
; /* Standard UI option */
150 ppd_choice_t
*choice
; /* Standard UI option choice */
151 struct lconv
*loc
; /* Locale data */
152 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
153 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
154 "JCL", "PAGE", "PROLOG" };
157 _cupsSetLocale(argv
);
161 * Display PPD files for each file listed on the command-line...
164 ppdSetConformance(PPD_CONFORM_STRICT
);
174 for (i
= 1; i
< argc
; i
++)
175 if (argv
[i
][0] == '-' && argv
[i
][1])
177 for (opt
= argv
[i
] + 1; *opt
; opt
++)
180 case 'I' : /* Ignore errors */
186 if (!strcmp(argv
[i
], "none"))
188 else if (!strcmp(argv
[i
], "filename"))
189 ignore
|= WARN_FILENAME
;
190 else if (!strcmp(argv
[i
], "filters"))
191 ignore
|= WARN_FILTERS
;
192 else if (!strcmp(argv
[i
], "profiles"))
193 ignore
|= WARN_PROFILES
;
194 else if (!strcmp(argv
[i
], "all"))
195 ignore
= WARN_FILTERS
| WARN_PROFILES
;
200 case 'R' : /* Alternate root directory */
209 case 'W' : /* Turn errors into warnings */
215 if (!strcmp(argv
[i
], "none"))
217 else if (!strcmp(argv
[i
], "constraints"))
218 warn
|= WARN_CONSTRAINTS
;
219 else if (!strcmp(argv
[i
], "defaults"))
220 warn
|= WARN_DEFAULTS
;
221 else if (!strcmp(argv
[i
], "duplex"))
223 else if (!strcmp(argv
[i
], "filters"))
224 warn
|= WARN_FILTERS
;
225 else if (!strcmp(argv
[i
], "profiles"))
226 warn
|= WARN_PROFILES
;
227 else if (!strcmp(argv
[i
], "sizes"))
229 else if (!strcmp(argv
[i
], "translations"))
230 warn
|= WARN_TRANSLATIONS
;
231 else if (!strcmp(argv
[i
], "all"))
237 case 'q' : /* Quiet mode */
240 _cupsLangPuts(stderr
,
241 _("cupstestppd: The -q option is incompatible "
242 "with the -v option."));
249 case 'r' : /* Relaxed mode */
250 ppdSetConformance(PPD_CONFORM_RELAXED
);
253 case 'v' : /* Verbose mode */
256 _cupsLangPuts(stderr
,
257 _("cupstestppd: The -v option is incompatible "
258 "with the -q option."));
273 * Open the PPD file...
276 if (files
&& verbose
>= 0)
281 if (argv
[i
][0] == '-')
287 ppd
= _ppdOpen(cupsFileStdin(), _PPD_LOCALIZATION_ALL
);
290 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
295 * Read from a file...
299 printf("%s:", argv
[i
]);
301 if ((fp
= cupsFileOpen(argv
[i
], "r")) != NULL
)
303 ppd
= _ppdOpen(fp
, _PPD_LOCALIZATION_ALL
);
308 status
= ERROR_FILE_OPEN
;
312 _cupsLangPuts(stdout
, _(" FAIL"));
313 _cupsLangPrintf(stdout
,
314 _(" **FAIL** Unable to open PPD file - %s on "
315 "line %d."), strerror(errno
), 0);
323 error
= ppdLastError(&line
);
325 if (error
<= PPD_ALLOC_ERROR
)
327 status
= ERROR_FILE_OPEN
;
331 _cupsLangPuts(stdout
, _(" FAIL"));
332 _cupsLangPrintf(stdout
,
333 _(" **FAIL** Unable to open PPD file - %s on "
334 "line %d."), strerror(errno
), 0);
339 status
= ERROR_PPD_FORMAT
;
343 _cupsLangPuts(stdout
, _(" FAIL"));
344 _cupsLangPrintf(stdout
,
345 _(" **FAIL** Unable to open PPD file - "
347 ppdErrorString(error
), line
);
351 case PPD_MISSING_PPDADOBE4
:
352 _cupsLangPuts(stdout
,
353 _(" REF: Page 42, section "
356 case PPD_MISSING_VALUE
:
357 _cupsLangPuts(stdout
,
358 _(" REF: Page 20, section "
361 case PPD_BAD_OPEN_GROUP
:
362 case PPD_NESTED_OPEN_GROUP
:
363 _cupsLangPuts(stdout
,
364 _(" REF: Pages 45-46, section "
367 case PPD_BAD_OPEN_UI
:
368 case PPD_NESTED_OPEN_UI
:
369 _cupsLangPuts(stdout
,
370 _(" REF: Pages 42-45, section "
373 case PPD_BAD_ORDER_DEPENDENCY
:
374 _cupsLangPuts(stdout
,
375 _(" REF: Pages 48-49, section "
378 case PPD_BAD_UI_CONSTRAINTS
:
379 _cupsLangPuts(stdout
,
380 _(" REF: Pages 52-54, section "
383 case PPD_MISSING_ASTERISK
:
384 _cupsLangPuts(stdout
,
385 _(" REF: Page 15, section "
388 case PPD_LINE_TOO_LONG
:
389 _cupsLangPuts(stdout
,
390 _(" REF: Page 15, section "
393 case PPD_ILLEGAL_CHARACTER
:
394 _cupsLangPuts(stdout
,
395 _(" REF: Page 15, section "
398 case PPD_ILLEGAL_MAIN_KEYWORD
:
399 _cupsLangPuts(stdout
,
400 _(" REF: Pages 16-17, section "
403 case PPD_ILLEGAL_OPTION_KEYWORD
:
404 _cupsLangPuts(stdout
,
405 _(" REF: Page 19, section "
408 case PPD_ILLEGAL_TRANSLATION
:
409 _cupsLangPuts(stdout
,
410 _(" REF: Page 27, section "
417 check_basics(argv
[i
]);
425 * Show the header and then perform basic conformance tests (limited
426 * only by what the CUPS PPD functions actually load...)
433 _cupsLangPuts(stdout
,
434 _("\n DETAILED CONFORMANCE TEST RESULTS"));
436 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
438 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
440 if ((attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
)) != NULL
)
444 if (strstr(attr
->value
, "application/vnd.cups-raster"))
446 if (!test_raster(ppd
, verbose
))
451 while ((attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
)) != NULL
);
455 for (j
= 0; j
< ppd
->num_filters
; j
++)
456 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
458 if (!test_raster(ppd
, verbose
))
465 * Look for default keywords with no matching option...
468 if (!(warn
& WARN_DEFAULTS
))
469 errors
= check_defaults(ppd
, errors
, verbose
, 0);
471 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
475 if (!errors
&& !verbose
)
476 _cupsLangPuts(stdout
, _(" FAIL"));
478 _cupsLangPuts(stdout
,
479 _(" **FAIL** REQUIRED DefaultImageableArea\n"
480 " REF: Page 102, section 5.15."));
485 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
486 strcmp(attr
->value
, "Unknown"))
490 if (!errors
&& !verbose
)
491 _cupsLangPuts(stdout
, _(" FAIL"));
493 _cupsLangPrintf(stdout
,
494 _(" **FAIL** Bad DefaultImageableArea %s\n"
495 " REF: Page 102, section 5.15."),
504 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea"));
507 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
511 if (!errors
&& !verbose
)
512 _cupsLangPuts(stdout
, _(" FAIL"));
514 _cupsLangPuts(stdout
,
515 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
516 " REF: Page 103, section 5.15."));
521 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
522 strcmp(attr
->value
, "Unknown"))
526 if (!errors
&& !verbose
)
527 _cupsLangPuts(stdout
, _(" FAIL"));
529 _cupsLangPrintf(stdout
,
530 _(" **FAIL** Bad DefaultPaperDimension %s\n"
531 " REF: Page 103, section 5.15."),
537 else if (verbose
> 0)
538 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension"));
540 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
541 for (k
= 0, option
= group
->options
;
542 k
< group
->num_options
;
546 * Verify that we have a default choice...
549 if (option
->defchoice
[0])
551 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
552 strcmp(option
->defchoice
, "Unknown"))
556 if (!errors
&& !verbose
)
557 _cupsLangPuts(stdout
, _(" FAIL"));
559 _cupsLangPrintf(stdout
,
560 _(" **FAIL** Bad Default%s %s\n"
561 " REF: Page 40, section 4.5."),
562 option
->keyword
, option
->defchoice
);
567 else if (verbose
> 0)
568 _cupsLangPrintf(stdout
,
569 _(" PASS Default%s"),
576 if (!errors
&& !verbose
)
577 _cupsLangPuts(stdout
, _(" FAIL"));
579 _cupsLangPrintf(stdout
,
580 _(" **FAIL** REQUIRED Default%s\n"
581 " REF: Page 40, section 4.5."),
589 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
591 for (ptr
= attr
->value
; *ptr
; ptr
++)
592 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
599 if (!errors
&& !verbose
)
600 _cupsLangPuts(stdout
, _(" FAIL"));
602 _cupsLangPrintf(stdout
,
603 _(" **FAIL** Bad FileVersion \"%s\"\n"
604 " REF: Page 56, section 5.3."),
610 else if (verbose
> 0)
611 _cupsLangPuts(stdout
, _(" PASS FileVersion"));
617 if (!errors
&& !verbose
)
618 _cupsLangPuts(stdout
, _(" FAIL"));
620 _cupsLangPuts(stdout
,
621 _(" **FAIL** REQUIRED FileVersion\n"
622 " REF: Page 56, section 5.3."));
628 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
631 if (*ptr
== '4' && ptr
[1] == '.')
634 for (ptr
+= 2; *ptr
; ptr
++)
635 if (!isdigit(*ptr
& 255))
643 if (!errors
&& !verbose
)
644 _cupsLangPuts(stdout
, _(" FAIL"));
646 _cupsLangPrintf(stdout
,
647 _(" **FAIL** Bad FormatVersion \"%s\"\n"
648 " REF: Page 56, section 5.3."),
654 else if (verbose
> 0)
655 _cupsLangPuts(stdout
, _(" PASS FormatVersion"));
661 if (!errors
&& !verbose
)
662 _cupsLangPuts(stdout
, _(" FAIL"));
664 _cupsLangPuts(stdout
,
665 _(" **FAIL** REQUIRED FormatVersion\n"
666 " REF: Page 56, section 5.3."));
672 if (ppd
->lang_encoding
!= NULL
)
675 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding"));
677 else if (ppdversion
> 40)
681 if (!errors
&& !verbose
)
682 _cupsLangPuts(stdout
, _(" FAIL"));
684 _cupsLangPuts(stdout
,
685 _(" **FAIL** REQUIRED LanguageEncoding\n"
686 " REF: Pages 56-57, section 5.3."));
692 if (ppd
->lang_version
!= NULL
)
695 _cupsLangPuts(stdout
, _(" PASS LanguageVersion"));
701 if (!errors
&& !verbose
)
702 _cupsLangPuts(stdout
, _(" FAIL"));
704 _cupsLangPuts(stdout
,
705 _(" **FAIL** REQUIRED LanguageVersion\n"
706 " REF: Pages 57-58, section 5.3."));
712 if (ppd
->manufacturer
!= NULL
)
714 if (!_cups_strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
715 !_cups_strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
719 if (!errors
&& !verbose
)
720 _cupsLangPuts(stdout
, _(" FAIL"));
722 _cupsLangPrintf(stdout
,
723 _(" **FAIL** Bad Manufacturer (should be "
725 " REF: Page 211, table D.1."),
731 else if (!_cups_strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
732 !_cups_strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
736 if (!errors
&& !verbose
)
737 _cupsLangPuts(stdout
, _(" FAIL"));
739 _cupsLangPrintf(stdout
,
740 _(" **FAIL** Bad Manufacturer (should be "
742 " REF: Page 211, table D.1."),
748 else if (verbose
> 0)
749 _cupsLangPuts(stdout
, _(" PASS Manufacturer"));
751 else if (ppdversion
>= 43)
755 if (!errors
&& !verbose
)
756 _cupsLangPuts(stdout
, _(" FAIL"));
758 _cupsLangPuts(stdout
,
759 _(" **FAIL** REQUIRED Manufacturer\n"
760 " REF: Pages 58-59, section 5.3."));
766 if (ppd
->modelname
!= NULL
)
768 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
769 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
776 if (!errors
&& !verbose
)
777 _cupsLangPuts(stdout
, _(" FAIL"));
779 _cupsLangPrintf(stdout
,
780 _(" **FAIL** Bad ModelName - \"%c\" not "
781 "allowed in string.\n"
782 " REF: Pages 59-60, section 5.3."),
788 else if (verbose
> 0)
789 _cupsLangPuts(stdout
, _(" PASS ModelName"));
795 if (!errors
&& !verbose
)
796 _cupsLangPuts(stdout
, _(" FAIL"));
798 _cupsLangPuts(stdout
,
799 _(" **FAIL** REQUIRED ModelName\n"
800 " REF: Pages 59-60, section 5.3."));
806 if (ppd
->nickname
!= NULL
)
809 _cupsLangPuts(stdout
, _(" PASS NickName"));
815 if (!errors
&& !verbose
)
816 _cupsLangPuts(stdout
, _(" FAIL"));
818 _cupsLangPuts(stdout
,
819 _(" **FAIL** REQUIRED NickName\n"
820 " REF: Page 60, section 5.3."));
826 if (ppdFindOption(ppd
, "PageSize") != NULL
)
829 _cupsLangPuts(stdout
, _(" PASS PageSize"));
835 if (!errors
&& !verbose
)
836 _cupsLangPuts(stdout
, _(" FAIL"));
838 _cupsLangPuts(stdout
,
839 _(" **FAIL** REQUIRED PageSize\n"
840 " REF: Pages 99-100, section 5.14."));
846 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
849 _cupsLangPuts(stdout
, _(" PASS PageRegion"));
855 if (!errors
&& !verbose
)
856 _cupsLangPuts(stdout
, _(" FAIL"));
858 _cupsLangPuts(stdout
,
859 _(" **FAIL** REQUIRED PageRegion\n"
860 " REF: Page 100, section 5.14."));
866 if (ppd
->pcfilename
!= NULL
)
869 _cupsLangPuts(stdout
, _(" PASS PCFileName"));
871 else if (!(ignore
& WARN_FILENAME
))
875 if (!errors
&& !verbose
)
876 _cupsLangPuts(stdout
, _(" FAIL"));
878 _cupsLangPuts(stdout
,
879 _(" **FAIL** REQUIRED PCFileName\n"
880 " REF: Pages 61-62, section 5.3."));
886 if (ppd
->product
!= NULL
)
888 if (ppd
->product
[0] != '(' ||
889 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
893 if (!errors
&& !verbose
)
894 _cupsLangPuts(stdout
, _(" FAIL"));
896 _cupsLangPuts(stdout
,
897 _(" **FAIL** Bad Product - not \"(string)\".\n"
898 " REF: Page 62, section 5.3."));
903 else if (verbose
> 0)
904 _cupsLangPuts(stdout
, _(" PASS Product"));
910 if (!errors
&& !verbose
)
911 _cupsLangPuts(stdout
, _(" FAIL"));
913 _cupsLangPuts(stdout
,
914 _(" **FAIL** REQUIRED Product\n"
915 " REF: Page 62, section 5.3."));
921 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
924 char junkstr
[255]; /* Temp string */
925 int junkint
; /* Temp integer */
928 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
932 if (!errors
&& !verbose
)
933 _cupsLangPuts(stdout
, _(" FAIL"));
935 _cupsLangPuts(stdout
,
936 _(" **FAIL** Bad PSVersion - not \"(string) "
938 " REF: Pages 62-64, section 5.3."));
943 else if (verbose
> 0)
944 _cupsLangPuts(stdout
, _(" PASS PSVersion"));
950 if (!errors
&& !verbose
)
951 _cupsLangPuts(stdout
, _(" FAIL"));
953 _cupsLangPuts(stdout
,
954 _(" **FAIL** REQUIRED PSVersion\n"
955 " REF: Pages 62-64, section 5.3."));
961 if (ppd
->shortnickname
!= NULL
)
963 if (strlen(ppd
->shortnickname
) > 31)
967 if (!errors
&& !verbose
)
968 _cupsLangPuts(stdout
, _(" FAIL"));
970 _cupsLangPuts(stdout
,
971 _(" **FAIL** Bad ShortNickName - longer "
973 " REF: Pages 64-65, section 5.3."));
978 else if (verbose
> 0)
979 _cupsLangPuts(stdout
, _(" PASS ShortNickName"));
981 else if (ppdversion
>= 43)
985 if (!errors
&& !verbose
)
986 _cupsLangPuts(stdout
, _(" FAIL"));
988 _cupsLangPuts(stdout
,
989 _(" **FAIL** REQUIRED ShortNickName\n"
990 " REF: Page 64-65, section 5.3."));
996 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
997 strstr(ppd
->patches
, "*End"))
1001 if (!errors
&& !verbose
)
1002 _cupsLangPuts(stdout
, _(" FAIL"));
1004 _cupsLangPuts(stdout
,
1005 _(" **FAIL** Bad JobPatchFile attribute in file\n"
1006 " REF: Page 24, section 3.4."));
1013 * Check for page sizes without the corresponding ImageableArea or
1014 * PaperDimension values...
1017 if (ppd
->num_sizes
== 0)
1021 if (!errors
&& !verbose
)
1022 _cupsLangPuts(stdout
, _(" FAIL"));
1024 _cupsLangPuts(stdout
,
1025 _(" **FAIL** REQUIRED PageSize\n"
1026 " REF: Page 41, section 5.\n"
1027 " REF: Page 99, section 5.14."));
1034 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1037 * Don't check custom size...
1040 if (!strcmp(size
->name
, "Custom"))
1044 * Check for ImageableArea...
1047 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1048 size
->right
== 0.0 && size
->top
== 0.0)
1052 if (!errors
&& !verbose
)
1053 _cupsLangPuts(stdout
, _(" FAIL"));
1055 _cupsLangPrintf(stdout
,
1056 _(" **FAIL** REQUIRED ImageableArea for "
1058 " REF: Page 41, section 5.\n"
1059 " REF: Page 102, section 5.15."),
1067 * Check for PaperDimension...
1070 if (size
->width
<= 0.0 && size
->length
<= 0.0)
1074 if (!errors
&& !verbose
)
1075 _cupsLangPuts(stdout
, _(" FAIL"));
1077 _cupsLangPrintf(stdout
,
1078 _(" **FAIL** REQUIRED PaperDimension "
1080 " REF: Page 41, section 5.\n"
1081 " REF: Page 103, section 5.15."),
1091 * Check for valid Resolution, JCLResolution, or SetResolution values...
1094 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1095 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1096 option
= ppdFindOption(ppd
, "SetResolution");
1100 for (j
= option
->num_choices
, choice
= option
->choices
;
1105 * Verify that all resolution options are of the form NNNdpi
1109 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1110 if (ptr
> choice
->choice
&& xdpi
> 0)
1113 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1120 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1125 if (!errors
&& !verbose
)
1126 _cupsLangPuts(stdout
, _(" FAIL"));
1128 _cupsLangPrintf(stdout
,
1129 _(" **FAIL** Bad option %s choice %s\n"
1130 " REF: Page 84, section 5.9"),
1131 option
->keyword
, choice
->choice
);
1139 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1140 strcmp(attr
->name
, "1284DeviceID"))
1144 if (!errors
&& !verbose
)
1145 _cupsLangPuts(stdout
, _(" FAIL"));
1147 _cupsLangPrintf(stdout
,
1148 _(" **FAIL** %s must be 1284DeviceID\n"
1149 " REF: Page 72, section 5.5"),
1156 errors
= check_case(ppd
, errors
, verbose
);
1158 if (!(warn
& WARN_CONSTRAINTS
))
1159 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1161 if (!(warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1162 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1164 if (!(warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1165 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1167 if (!(warn
& WARN_SIZES
))
1168 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1170 if (!(warn
& WARN_TRANSLATIONS
))
1171 errors
= check_translations(ppd
, errors
, verbose
, 0);
1173 if (!(warn
& WARN_DUPLEX
))
1174 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1176 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1180 * This file contains localizations, check for conformance of the
1181 * base translation...
1184 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1186 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1188 if (!errors
&& !verbose
)
1189 _cupsLangPuts(stdout
, _(" FAIL"));
1192 _cupsLangPrintf(stdout
,
1193 _(" **FAIL** Bad LanguageEncoding %s - "
1194 "must be ISOLatin1."),
1195 attr
->value
? attr
->value
: "(null)");
1200 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1202 if (!errors
&& !verbose
)
1203 _cupsLangPuts(stdout
, _(" FAIL"));
1206 _cupsLangPrintf(stdout
,
1207 _(" **FAIL** Bad LanguageVersion %s - "
1208 "must be English."),
1209 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1215 * Loop through all options and choices...
1218 for (option
= ppdFirstOption(ppd
);
1220 option
= ppdNextOption(ppd
))
1223 * Check for special characters outside A0 to BF, F7, or F8
1224 * that are used for languages other than English.
1227 for (ptr
= option
->text
; *ptr
; ptr
++)
1228 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1229 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1234 if (!errors
&& !verbose
)
1235 _cupsLangPuts(stdout
, _(" FAIL"));
1238 _cupsLangPrintf(stdout
,
1239 _(" **FAIL** Default translation "
1240 "string for option %s contains 8-bit "
1247 for (j
= 0; j
< option
->num_choices
; j
++)
1250 * Check for special characters outside A0 to BF, F7, or F8
1251 * that are used for languages other than English.
1254 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1255 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1256 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1261 if (!errors
&& !verbose
)
1262 _cupsLangPuts(stdout
, _(" FAIL"));
1265 _cupsLangPrintf(stdout
,
1266 _(" **FAIL** Default translation "
1267 "string for option %s choice %s contains "
1268 "8-bit characters."),
1270 option
->choices
[j
].choice
);
1280 * Final pass/fail notification...
1284 status
= ERROR_CONFORMANCE
;
1286 _cupsLangPuts(stdout
, _(" PASS"));
1290 check_basics(argv
[i
]);
1292 if (warn
& WARN_DEFAULTS
)
1293 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1295 if (warn
& WARN_CONSTRAINTS
)
1296 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1298 if ((warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1299 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1301 if ((warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1302 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1304 if (warn
& WARN_SIZES
)
1305 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1307 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1309 if (warn
& WARN_TRANSLATIONS
)
1310 errors
= check_translations(ppd
, errors
, verbose
, 1);
1312 if (warn
& WARN_DUPLEX
)
1313 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1316 * Look for legacy duplex keywords...
1319 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1320 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1321 option
= ppdFindOption(ppd
, "KD03Duplex");
1324 _cupsLangPrintf(stdout
,
1325 _(" WARN Duplex option keyword %s may not "
1326 "work as expected and should be named Duplex.\n"
1327 " REF: Page 122, section 5.17"),
1331 * Look for default keywords with no corresponding option...
1334 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1336 attr
= ppd
->attrs
[j
];
1338 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1339 !strcmp(attr
->name
, "DefaultColorSep") ||
1340 !strcmp(attr
->name
, "DefaultFont") ||
1341 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1342 !strcmp(attr
->name
, "DefaultImageableArea") ||
1343 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1344 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1345 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1346 !strcmp(attr
->name
, "DefaultResolution") ||
1347 !strcmp(attr
->name
, "DefaultScreenProc") ||
1348 !strcmp(attr
->name
, "DefaultTransfer"))
1351 if (!strncmp(attr
->name
, "Default", 7) &&
1352 !ppdFindOption(ppd
, attr
->name
+ 7))
1353 _cupsLangPrintf(stdout
,
1354 _(" WARN %s has no corresponding "
1359 if (ppdversion
< 43)
1361 _cupsLangPrintf(stdout
,
1362 _(" WARN Obsolete PPD version %.1f.\n"
1363 " REF: Page 42, section 5.2."),
1367 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1369 _cupsLangPuts(stdout
,
1370 _(" WARN LanguageEncoding required by PPD "
1372 " REF: Pages 56-57, section 5.3."));
1375 if (!ppd
->manufacturer
&& ppdversion
< 43)
1377 _cupsLangPuts(stdout
,
1378 _(" WARN Manufacturer required by PPD "
1380 " REF: Pages 58-59, section 5.3."));
1384 * Treat a PCFileName attribute longer than 12 characters as
1385 * a warning and not a hard error...
1388 if (!(ignore
& WARN_FILENAME
) && ppd
->pcfilename
)
1390 if (strlen(ppd
->pcfilename
) > 12)
1392 _cupsLangPuts(stdout
,
1393 _(" WARN PCFileName longer than 8.3 in "
1394 "violation of PPD spec.\n"
1395 " REF: Pages 61-62, section "
1399 if (!_cups_strcasecmp(ppd
->pcfilename
, "unused.ppd"))
1400 _cupsLangPuts(stdout
,
1401 _(" WARN PCFileName should contain a "
1402 "unique filename.\n"
1403 " REF: Pages 61-62, section "
1407 if (!ppd
->shortnickname
&& ppdversion
< 43)
1409 _cupsLangPuts(stdout
,
1410 _(" WARN ShortNickName required by PPD "
1412 " REF: Pages 64-65, section 5.3."));
1416 * Check the Protocols line and flag PJL + BCP since TBCP is
1417 * usually used with PJL...
1422 if (strstr(ppd
->protocols
, "PJL") &&
1423 strstr(ppd
->protocols
, "BCP") &&
1424 !strstr(ppd
->protocols
, "TBCP"))
1426 _cupsLangPuts(stdout
,
1427 _(" WARN Protocols contains both PJL "
1428 "and BCP; expected TBCP.\n"
1429 " REF: Pages 78-79, section 5.7."));
1432 if (strstr(ppd
->protocols
, "PJL") &&
1433 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1435 _cupsLangPuts(stdout
,
1436 _(" WARN Protocols contains PJL but JCL "
1437 "attributes are not set.\n"
1438 " REF: Pages 78-79, section 5.7."));
1443 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1444 * which are errors according to the spec but won't cause problems
1445 * with CUPS specifically...
1448 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1449 for (k
= 0, option
= group
->options
;
1450 k
< group
->num_options
;
1453 len
= strlen(option
->keyword
);
1455 for (m
= 0, group2
= ppd
->groups
;
1456 m
< ppd
->num_groups
;
1458 for (n
= 0, option2
= group2
->options
;
1459 n
< group2
->num_options
;
1461 if (option
!= option2
&&
1462 len
< strlen(option2
->keyword
) &&
1463 !strncmp(option
->keyword
, option2
->keyword
, len
))
1465 _cupsLangPrintf(stdout
,
1466 _(" WARN %s shares a common "
1468 " REF: Page 15, section "
1470 option
->keyword
, option2
->keyword
);
1478 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND"), errors
);
1480 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND"));
1484 * Then list the options, if "-v" was provided...
1489 _cupsLangPrintf(stdout
,
1491 " language_level = %d\n"
1492 " color_device = %s\n"
1493 " variable_sizes = %s\n"
1495 ppd
->language_level
,
1496 ppd
->color_device
? "TRUE" : "FALSE",
1497 ppd
->variable_sizes
? "TRUE" : "FALSE",
1500 switch (ppd
->colorspace
)
1503 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK");
1506 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY");
1509 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY");
1512 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB");
1515 _cupsLangPuts(stdout
, " colorspace = <unknown>");
1519 _cupsLangPrintf(stdout
, " num_emulations = %d",
1520 ppd
->num_emulations
);
1521 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1522 _cupsLangPrintf(stdout
, " emulations[%d] = %s",
1523 j
, ppd
->emulations
[j
].name
);
1525 _cupsLangPrintf(stdout
, " lang_encoding = %s",
1526 ppd
->lang_encoding
);
1527 _cupsLangPrintf(stdout
, " lang_version = %s",
1529 _cupsLangPrintf(stdout
, " modelname = %s", ppd
->modelname
);
1530 _cupsLangPrintf(stdout
, " ttrasterizer = %s",
1531 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1532 _cupsLangPrintf(stdout
, " manufacturer = %s",
1534 _cupsLangPrintf(stdout
, " product = %s", ppd
->product
);
1535 _cupsLangPrintf(stdout
, " nickname = %s", ppd
->nickname
);
1536 _cupsLangPrintf(stdout
, " shortnickname = %s",
1537 ppd
->shortnickname
);
1538 _cupsLangPrintf(stdout
, " patches = %d bytes",
1539 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1541 _cupsLangPrintf(stdout
, " num_groups = %d", ppd
->num_groups
);
1542 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1544 _cupsLangPrintf(stdout
, " group[%d] = %s",
1547 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1549 _cupsLangPrintf(stdout
,
1550 " options[%d] = %s (%s) %s %s %.0f "
1552 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1553 sections
[option
->section
], option
->order
,
1554 option
->num_choices
);
1556 if (!strcmp(option
->keyword
, "PageSize") ||
1557 !strcmp(option
->keyword
, "PageRegion"))
1559 for (m
= option
->num_choices
, choice
= option
->choices
;
1563 size
= ppdPageSize(ppd
, choice
->choice
);
1566 _cupsLangPrintf(stdout
,
1567 " %s (%s) = ERROR%s",
1568 choice
->choice
, choice
->text
,
1569 !strcmp(option
->defchoice
, choice
->choice
)
1572 _cupsLangPrintf(stdout
,
1573 " %s (%s) = %.2fx%.2fin "
1574 "(%.1f,%.1f,%.1f,%.1f)%s",
1575 choice
->choice
, choice
->text
,
1576 size
->width
/ 72.0, size
->length
/ 72.0,
1577 size
->left
/ 72.0, size
->bottom
/ 72.0,
1578 size
->right
/ 72.0, size
->top
/ 72.0,
1579 !strcmp(option
->defchoice
, choice
->choice
)
1585 for (m
= option
->num_choices
, choice
= option
->choices
;
1589 _cupsLangPrintf(stdout
, " %s (%s)%s",
1590 choice
->choice
, choice
->text
,
1591 !strcmp(option
->defchoice
, choice
->choice
)
1598 _cupsLangPrintf(stdout
, " num_consts = %d",
1600 for (j
= 0; j
< ppd
->num_consts
; j
++)
1601 _cupsLangPrintf(stdout
,
1602 " consts[%d] = *%s %s *%s %s",
1603 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1604 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1606 _cupsLangPrintf(stdout
, " num_profiles = %d",
1608 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1609 _cupsLangPrintf(stdout
,
1610 " profiles[%d] = %s/%s %.3f %.3f "
1611 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]",
1612 j
, ppd
->profiles
[j
].resolution
,
1613 ppd
->profiles
[j
].media_type
,
1614 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1615 ppd
->profiles
[j
].matrix
[0][0],
1616 ppd
->profiles
[j
].matrix
[0][1],
1617 ppd
->profiles
[j
].matrix
[0][2],
1618 ppd
->profiles
[j
].matrix
[1][0],
1619 ppd
->profiles
[j
].matrix
[1][1],
1620 ppd
->profiles
[j
].matrix
[1][2],
1621 ppd
->profiles
[j
].matrix
[2][0],
1622 ppd
->profiles
[j
].matrix
[2][1],
1623 ppd
->profiles
[j
].matrix
[2][2]);
1625 _cupsLangPrintf(stdout
, " num_fonts = %d", ppd
->num_fonts
);
1626 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1627 _cupsLangPrintf(stdout
, " fonts[%d] = %s",
1630 _cupsLangPrintf(stdout
, " num_attrs = %d", ppd
->num_attrs
);
1631 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1632 _cupsLangPrintf(stdout
,
1633 " attrs[%d] = %s %s%s%s: \"%s\"", j
,
1634 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1635 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1636 ppd
->attrs
[j
]->text
,
1637 ppd
->attrs
[j
]->value
?
1638 ppd
->attrs
[j
]->value
: "(null)");
1652 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1656 check_basics(const char *filename
) /* I - PPD file to check */
1658 cups_file_t
*fp
; /* File pointer */
1659 int ch
; /* Current character */
1660 int col
, /* Current column */
1661 whitespace
; /* Only seen whitespace? */
1662 int eol
; /* Line endings */
1663 int linenum
; /* Line number */
1664 int mixed
; /* Mixed line endings? */
1667 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1676 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1678 if (ch
== '\r' || ch
== '\n')
1682 if (eol
== EOL_NONE
)
1684 else if (eol
!= EOL_LF
)
1687 else if (ch
== '\r')
1689 if (cupsFilePeekChar(fp
) == '\n')
1691 cupsFileGetChar(fp
);
1693 if (eol
== EOL_NONE
)
1695 else if (eol
!= EOL_CRLF
)
1698 else if (eol
== EOL_NONE
)
1700 else if (eol
!= EOL_CR
)
1704 if (col
> 0 && whitespace
)
1705 _cupsLangPrintf(stdout
,
1706 _(" WARN Line %d only contains whitespace."),
1715 if (ch
!= ' ' && ch
!= '\t')
1723 _cupsLangPuts(stdout
,
1724 _(" WARN File contains a mix of CR, LF, and "
1725 "CR LF line endings."));
1727 if (eol
== EOL_CRLF
)
1728 _cupsLangPuts(stdout
,
1729 _(" WARN Non-Windows PPD files should use lines "
1730 "ending with only LF, not CR LF."));
1737 * 'check_constraints()' - Check UIConstraints in the PPD file.
1740 static int /* O - Errors found */
1741 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1742 int errors
, /* I - Errors found */
1743 int verbose
, /* I - Verbosity level */
1744 int warn
) /* I - Warnings only? */
1746 int i
; /* Looping var */
1747 const char *prefix
; /* WARN/FAIL prefix */
1748 ppd_const_t
*c
; /* Current UIConstraints data */
1749 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1750 const char *vptr
; /* Pointer into constraint value */
1751 char option
[PPD_MAX_NAME
],
1752 /* Option name/MainKeyword */
1753 choice
[PPD_MAX_NAME
],
1754 /* Choice/OptionKeyword */
1755 *ptr
; /* Pointer into option or choice */
1756 int num_options
; /* Number of options */
1757 cups_option_t
*options
; /* Options */
1758 ppd_option_t
*o
; /* PPD option */
1761 prefix
= warn
? " WARN " : "**FAIL**";
1765 * See what kind of constraint data we have in the PPD...
1768 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1771 * Check new-style cupsUIConstraints data...
1775 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1777 if (!constattr
->value
)
1779 if (!warn
&& !errors
&& !verbose
)
1780 _cupsLangPuts(stdout
, _(" FAIL"));
1782 _cupsLangPrintf(stdout
,
1783 _(" %s Empty cupsUIConstraints %s"),
1784 prefix
, constattr
->spec
);
1792 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1794 i
++, vptr
= strchr(vptr
+ 1, '*'));
1798 if (!warn
&& !errors
&& !verbose
)
1799 _cupsLangPuts(stdout
, _(" FAIL"));
1801 _cupsLangPrintf(stdout
,
1802 _(" %s Bad cupsUIConstraints %s: \"%s\""),
1803 prefix
, constattr
->spec
, constattr
->value
);
1811 cupsArraySave(ppd
->sorted_attrs
);
1813 if (constattr
->spec
[0] &&
1814 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1816 if (!warn
&& !errors
&& !verbose
)
1817 _cupsLangPuts(stdout
, _(" FAIL"));
1819 _cupsLangPrintf(stdout
,
1820 _(" %s Missing cupsUIResolver %s"),
1821 prefix
, constattr
->spec
);
1827 cupsArrayRestore(ppd
->sorted_attrs
);
1832 for (vptr
= strchr(constattr
->value
, '*');
1834 vptr
= strchr(vptr
, '*'))
1837 * Extract "*Option Choice" or just "*Option"...
1840 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1841 if (ptr
< (option
+ sizeof(option
) - 1))
1846 while (isspace(*vptr
& 255))
1853 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1854 if (ptr
< (choice
+ sizeof(choice
) - 1))
1860 if (!_cups_strncasecmp(option
, "Custom", 6) && !_cups_strcasecmp(choice
, "True"))
1862 _cups_strcpy(option
, option
+ 6);
1863 strlcpy(choice
, "Custom", sizeof(choice
));
1866 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1868 if (!warn
&& !errors
&& !verbose
)
1869 _cupsLangPuts(stdout
, _(" FAIL"));
1871 _cupsLangPrintf(stdout
,
1872 _(" %s Missing option %s in "
1873 "cupsUIConstraints %s: \"%s\""),
1874 prefix
, option
, constattr
->spec
, constattr
->value
);
1882 if (choice
[0] && !ppdFindChoice(o
, choice
))
1884 if (!warn
&& !errors
&& !verbose
)
1885 _cupsLangPuts(stdout
, _(" FAIL"));
1887 _cupsLangPrintf(stdout
,
1888 _(" %s Missing choice *%s %s in "
1889 "cupsUIConstraints %s: \"%s\""),
1890 prefix
, option
, choice
, constattr
->spec
,
1900 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1903 for (i
= 0; i
< o
->num_choices
; i
++)
1904 if (_cups_strcasecmp(o
->choices
[i
].choice
, "None") &&
1905 _cups_strcasecmp(o
->choices
[i
].choice
, "Off") &&
1906 _cups_strcasecmp(o
->choices
[i
].choice
, "False"))
1908 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
1909 num_options
, &options
);
1916 * Resolvers must list at least two options...
1919 if (num_options
< 2)
1921 if (!warn
&& !errors
&& !verbose
)
1922 _cupsLangPuts(stdout
, _(" FAIL"));
1924 _cupsLangPrintf(stdout
,
1925 _(" %s cupsUIResolver %s does not list at least "
1926 "two different options."),
1927 prefix
, constattr
->spec
);
1934 * Test the resolver...
1937 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
1939 if (!warn
&& !errors
&& !verbose
)
1940 _cupsLangPuts(stdout
, _(" FAIL"));
1942 _cupsLangPrintf(stdout
,
1943 _(" %s cupsUIResolver %s causes a loop."),
1944 prefix
, constattr
->spec
);
1950 cupsFreeOptions(num_options
, options
);
1956 * Check old-style [Non]UIConstraints data...
1959 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1961 if (!_cups_strncasecmp(c
->option1
, "Custom", 6) &&
1962 !_cups_strcasecmp(c
->choice1
, "True"))
1964 strlcpy(option
, c
->option1
+ 6, sizeof(option
));
1965 strlcpy(choice
, "Custom", sizeof(choice
));
1969 strlcpy(option
, c
->option1
, sizeof(option
));
1970 strlcpy(choice
, c
->choice1
, sizeof(choice
));
1973 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1975 if (!warn
&& !errors
&& !verbose
)
1976 _cupsLangPuts(stdout
, _(" FAIL"));
1978 _cupsLangPrintf(stdout
,
1979 _(" %s Missing option %s in "
1980 "UIConstraints \"*%s %s *%s %s\"."),
1982 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1987 else if (choice
[0] && !ppdFindChoice(o
, choice
))
1989 if (!warn
&& !errors
&& !verbose
)
1990 _cupsLangPuts(stdout
, _(" FAIL"));
1992 _cupsLangPrintf(stdout
,
1993 _(" %s Missing choice *%s %s in "
1994 "UIConstraints \"*%s %s *%s %s\"."),
1995 prefix
, c
->option1
, c
->choice1
,
1996 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2002 if (!_cups_strncasecmp(c
->option2
, "Custom", 6) &&
2003 !_cups_strcasecmp(c
->choice2
, "True"))
2005 strlcpy(option
, c
->option2
+ 6, sizeof(option
));
2006 strlcpy(choice
, "Custom", sizeof(choice
));
2010 strlcpy(option
, c
->option2
, sizeof(option
));
2011 strlcpy(choice
, c
->choice2
, sizeof(choice
));
2014 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
2016 if (!warn
&& !errors
&& !verbose
)
2017 _cupsLangPuts(stdout
, _(" FAIL"));
2019 _cupsLangPrintf(stdout
,
2020 _(" %s Missing option %s in "
2021 "UIConstraints \"*%s %s *%s %s\"."),
2023 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2028 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2030 if (!warn
&& !errors
&& !verbose
)
2031 _cupsLangPuts(stdout
, _(" FAIL"));
2033 _cupsLangPrintf(stdout
,
2034 _(" %s Missing choice *%s %s in "
2035 "UIConstraints \"*%s %s *%s %s\"."),
2036 prefix
, c
->option2
, c
->choice2
,
2037 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2050 * 'check_case()' - Check that there are no duplicate groups, options,
2051 * or choices that differ only by case.
2054 static int /* O - Errors found */
2055 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2056 int errors
, /* I - Errors found */
2057 int verbose
) /* I - Verbosity level */
2059 int i
, j
; /* Looping vars */
2060 ppd_group_t
*groupa
, /* First group */
2061 *groupb
; /* Second group */
2062 ppd_option_t
*optiona
, /* First option */
2063 *optionb
; /* Second option */
2064 ppd_choice_t
*choicea
, /* First choice */
2065 *choiceb
; /* Second choice */
2069 * Check that the groups do not have any duplicate names...
2072 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2073 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2074 if (!_cups_strcasecmp(groupa
->name
, groupb
->name
))
2076 if (!errors
&& !verbose
)
2077 _cupsLangPuts(stdout
, _(" FAIL"));
2080 _cupsLangPrintf(stdout
,
2081 _(" **FAIL** Group names %s and %s differ only "
2083 groupa
->name
, groupb
->name
);
2089 * Check that the options do not have any duplicate names...
2092 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2094 cupsArraySave(ppd
->options
);
2095 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2096 if (!_cups_strcasecmp(optiona
->keyword
, optionb
->keyword
))
2098 if (!errors
&& !verbose
)
2099 _cupsLangPuts(stdout
, _(" FAIL"));
2102 _cupsLangPrintf(stdout
,
2103 _(" **FAIL** Option names %s and %s differ only "
2105 optiona
->keyword
, optionb
->keyword
);
2109 cupsArrayRestore(ppd
->options
);
2112 * Then the choices...
2115 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2118 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2119 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2121 if (!errors
&& !verbose
)
2122 _cupsLangPuts(stdout
, _(" FAIL"));
2125 _cupsLangPrintf(stdout
,
2126 _(" **FAIL** Multiple occurrences of "
2127 "option %s choice name %s."),
2128 optiona
->keyword
, choicea
->choice
);
2136 else if (!_cups_strcasecmp(choicea
->choice
, choiceb
->choice
))
2138 if (!errors
&& !verbose
)
2139 _cupsLangPuts(stdout
, _(" FAIL"));
2142 _cupsLangPrintf(stdout
,
2143 _(" **FAIL** Option %s choice names %s and "
2144 "%s differ only by case."),
2145 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2152 * Return the number of errors found...
2160 * 'check_defaults()' - Check default option keywords in the PPD file.
2163 static int /* O - Errors found */
2164 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2165 int errors
, /* I - Errors found */
2166 int verbose
, /* I - Verbosity level */
2167 int warn
) /* I - Warnings only? */
2169 int j
, k
; /* Looping vars */
2170 ppd_attr_t
*attr
; /* PPD attribute */
2171 ppd_option_t
*option
; /* Standard UI option */
2172 const char *prefix
; /* WARN/FAIL prefix */
2175 prefix
= warn
? " WARN " : "**FAIL**";
2177 ppdMarkDefaults(ppd
);
2178 if (ppdConflicts(ppd
))
2180 if (!warn
&& !errors
&& !verbose
)
2181 _cupsLangPuts(stdout
, _(" FAIL"));
2184 _cupsLangPrintf(stdout
,
2185 _(" %s Default choices conflicting."), prefix
);
2187 show_conflicts(ppd
, prefix
);
2193 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2195 attr
= ppd
->attrs
[j
];
2197 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2198 !strcmp(attr
->name
, "DefaultFont") ||
2199 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2200 !strcmp(attr
->name
, "DefaultImageableArea") ||
2201 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2202 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2203 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2204 !strcmp(attr
->name
, "DefaultResolution") ||
2205 !strcmp(attr
->name
, "DefaultTransfer"))
2208 if (!strncmp(attr
->name
, "Default", 7))
2210 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2211 strcmp(attr
->value
, "Unknown"))
2214 * Check that the default option value matches a choice...
2217 for (k
= 0; k
< option
->num_choices
; k
++)
2218 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2221 if (k
>= option
->num_choices
)
2223 if (!warn
&& !errors
&& !verbose
)
2224 _cupsLangPuts(stdout
, _(" FAIL"));
2227 _cupsLangPrintf(stdout
,
2228 _(" %s %s %s does not exist."),
2229 prefix
, attr
->name
, attr
->value
);
2243 * 'check_duplex()' - Check duplex keywords in the PPD file.
2246 static int /* O - Errors found */
2247 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2248 int errors
, /* I - Error found */
2249 int verbose
, /* I - Verbosity level */
2250 int warn
) /* I - Warnings only? */
2252 int i
; /* Looping var */
2253 ppd_option_t
*option
; /* PPD option */
2254 ppd_choice_t
*choice
; /* Current choice */
2255 const char *prefix
; /* Message prefix */
2258 prefix
= warn
? " WARN " : "**FAIL**";
2261 * Check for a duplex option, and for standard values...
2264 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2266 if (!ppdFindChoice(option
, "None"))
2270 if (!warn
&& !errors
&& !verbose
)
2271 _cupsLangPuts(stdout
, _(" FAIL"));
2273 _cupsLangPrintf(stdout
,
2274 _(" %s REQUIRED %s does not define "
2276 " REF: Page 122, section 5.17"),
2277 prefix
, option
->keyword
);
2284 for (i
= option
->num_choices
, choice
= option
->choices
;
2287 if (strcmp(choice
->choice
, "None") &&
2288 strcmp(choice
->choice
, "DuplexNoTumble") &&
2289 strcmp(choice
->choice
, "DuplexTumble") &&
2290 strcmp(choice
->choice
, "SimplexTumble"))
2294 if (!warn
&& !errors
&& !verbose
)
2295 _cupsLangPuts(stdout
, _(" FAIL"));
2297 _cupsLangPrintf(stdout
,
2298 _(" %s Bad %s choice %s.\n"
2299 " REF: Page 122, section 5.17"),
2300 prefix
, option
->keyword
, choice
->choice
);
2313 * 'check_filters()' - Check filters in the PPD file.
2316 static int /* O - Errors found */
2317 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2318 const char *root
, /* I - Root directory */
2319 int errors
, /* I - Errors found */
2320 int verbose
, /* I - Verbosity level */
2321 int warn
) /* I - Warnings only? */
2323 ppd_attr_t
*attr
; /* PPD attribute */
2324 const char *ptr
; /* Pointer into string */
2325 char super
[16], /* Super-type for filter */
2326 type
[256], /* Type for filter */
2327 dstsuper
[16], /* Destination super-type for filter */
2328 dsttype
[256], /* Destination type for filter */
2329 program
[1024], /* Program/filter name */
2330 pathprog
[1024]; /* Complete path to program/filter */
2331 int cost
; /* Cost of filter */
2332 const char *prefix
; /* WARN/FAIL prefix */
2333 struct stat fileinfo
; /* File information */
2336 prefix
= warn
? " WARN " : "**FAIL**";
2342 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
2344 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
2346 if (strcmp(attr
->name
, "cupsFilter"))
2348 if (!warn
&& !errors
&& !verbose
)
2349 _cupsLangPuts(stdout
, _(" FAIL"));
2352 _cupsLangPrintf(stdout
,
2353 _(" %s Bad spelling of %s - should be %s."),
2354 prefix
, attr
->name
, "cupsFilter");
2361 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2362 &cost
, program
) != 4)
2364 if (!warn
&& !errors
&& !verbose
)
2365 _cupsLangPuts(stdout
, _(" FAIL"));
2368 _cupsLangPrintf(stdout
,
2369 _(" %s Bad cupsFilter value \"%s\"."),
2370 prefix
, attr
->value
);
2378 if (!strncmp(program
, "maxsize(", 8))
2380 size_t maxsize
; /* Maximum file size */
2381 char *ptr
; /* Pointer into maxsize(nnnn) program */
2383 maxsize
= (size_t)strtoll(program
+ 8, &ptr
, 10);
2387 if (!warn
&& !errors
&& !verbose
)
2388 _cupsLangPuts(stdout
, _(" FAIL"));
2391 _cupsLangPrintf(stdout
,
2392 _(" %s Bad cupsFilter value \"%s\"."),
2393 prefix
, attr
->value
);
2402 while (_cups_isspace(*ptr
))
2405 _cups_strcpy(program
, ptr
);
2408 if (strcmp(program
, "-"))
2410 if (program
[0] == '/')
2411 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2414 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2415 ptr
= CUPS_SERVERBIN
;
2417 if (*ptr
== '/' || !*root
)
2418 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2421 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2425 if (stat(pathprog
, &fileinfo
))
2427 if (!warn
&& !errors
&& !verbose
)
2428 _cupsLangPuts(stdout
, _(" FAIL"));
2431 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2432 prefix
, "cupsFilter", pathprog
);
2437 else if (fileinfo
.st_uid
!= 0 ||
2438 (fileinfo
.st_mode
& MODE_WRITE
) ||
2439 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2441 if (!warn
&& !errors
&& !verbose
)
2442 _cupsLangPuts(stdout
, _(" FAIL"));
2445 _cupsLangPrintf(stdout
,
2446 _(" %s Bad permissions on %s file \"%s\"."),
2447 prefix
, "cupsFilter", pathprog
);
2453 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2461 for (attr
= ppdFindAttr(ppd
, "cupsFilter2", NULL
);
2463 attr
= ppdFindNextAttr(ppd
, "cupsFilter2", NULL
))
2465 if (strcmp(attr
->name
, "cupsFilter2"))
2467 if (!warn
&& !errors
&& !verbose
)
2468 _cupsLangPuts(stdout
, _(" FAIL"));
2471 _cupsLangPrintf(stdout
,
2472 _(" %s Bad spelling of %s - should be %s."),
2473 prefix
, attr
->name
, "cupsFilter2");
2480 sscanf(attr
->value
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
2481 super
, type
, dstsuper
, dsttype
, &cost
, program
) != 6)
2483 if (!warn
&& !errors
&& !verbose
)
2484 _cupsLangPuts(stdout
, _(" FAIL"));
2487 _cupsLangPrintf(stdout
,
2488 _(" %s Bad cupsFilter2 value \"%s\"."),
2489 prefix
, attr
->value
);
2497 if (!strncmp(program
, "maxsize(", 8))
2499 size_t maxsize
; /* Maximum file size */
2500 char *ptr
; /* Pointer into maxsize(nnnn) program */
2502 maxsize
= (size_t)strtoll(program
+ 8, &ptr
, 10);
2506 if (!warn
&& !errors
&& !verbose
)
2507 _cupsLangPuts(stdout
, _(" FAIL"));
2510 _cupsLangPrintf(stdout
,
2511 _(" %s Bad cupsFilter2 value \"%s\"."),
2512 prefix
, attr
->value
);
2521 while (_cups_isspace(*ptr
))
2524 _cups_strcpy(program
, ptr
);
2527 if (strcmp(program
, "-"))
2529 if (strncmp(program
, "maxsize(", 8) &&
2530 (ptr
= strchr(program
+ 8, ')')) != NULL
)
2533 while (_cups_isspace(*ptr
))
2536 _cups_strcpy(program
, ptr
);
2539 if (program
[0] == '/')
2540 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2543 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2544 ptr
= CUPS_SERVERBIN
;
2546 if (*ptr
== '/' || !*root
)
2547 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2550 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2554 if (stat(pathprog
, &fileinfo
))
2556 if (!warn
&& !errors
&& !verbose
)
2557 _cupsLangPuts(stdout
, _(" FAIL"));
2560 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2561 prefix
, "cupsFilter2", pathprog
);
2566 else if (fileinfo
.st_uid
!= 0 ||
2567 (fileinfo
.st_mode
& MODE_WRITE
) ||
2568 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2570 if (!warn
&& !errors
&& !verbose
)
2571 _cupsLangPuts(stdout
, _(" FAIL"));
2574 _cupsLangPrintf(stdout
,
2575 _(" %s Bad permissions on %s file \"%s\"."),
2576 prefix
, "cupsFilter2", pathprog
);
2582 errors
= valid_path("cupsFilter2", pathprog
, errors
, verbose
, warn
);
2590 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2592 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2594 if (strcmp(attr
->name
, "cupsPreFilter"))
2596 if (!warn
&& !errors
&& !verbose
)
2597 _cupsLangPuts(stdout
, _(" FAIL"));
2600 _cupsLangPrintf(stdout
,
2601 _(" %s Bad spelling of %s - should be %s."),
2602 prefix
, attr
->name
, "cupsPreFilter");
2609 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2610 &cost
, program
) != 4)
2612 if (!warn
&& !errors
&& !verbose
)
2613 _cupsLangPuts(stdout
, _(" FAIL"));
2616 _cupsLangPrintf(stdout
,
2617 _(" %s Bad cupsPreFilter value \"%s\"."),
2618 prefix
, attr
->value
? attr
->value
: "");
2623 else if (strcmp(program
, "-"))
2625 if (program
[0] == '/')
2626 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2629 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2630 ptr
= CUPS_SERVERBIN
;
2632 if (*ptr
== '/' || !*root
)
2633 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2636 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2640 if (stat(pathprog
, &fileinfo
))
2642 if (!warn
&& !errors
&& !verbose
)
2643 _cupsLangPuts(stdout
, _(" FAIL"));
2646 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2647 prefix
, "cupsPreFilter", pathprog
);
2652 else if (fileinfo
.st_uid
!= 0 ||
2653 (fileinfo
.st_mode
& MODE_WRITE
) ||
2654 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2656 if (!warn
&& !errors
&& !verbose
)
2657 _cupsLangPuts(stdout
, _(" FAIL"));
2660 _cupsLangPrintf(stdout
,
2661 _(" %s Bad permissions on %s file \"%s\"."),
2662 prefix
, "cupsPreFilter", pathprog
);
2668 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2677 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2679 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2681 if (strcmp(attr
->name
, "APDialogExtension"))
2683 if (!warn
&& !errors
&& !verbose
)
2684 _cupsLangPuts(stdout
, _(" FAIL"));
2687 _cupsLangPrintf(stdout
,
2688 _(" %s Bad spelling of %s - should be %s."),
2689 prefix
, attr
->name
, "APDialogExtension");
2695 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2696 attr
->value
? attr
->value
: "(null)");
2698 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2700 if (!warn
&& !errors
&& !verbose
)
2701 _cupsLangPuts(stdout
, _(" FAIL"));
2704 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2705 prefix
, "APDialogExtension", pathprog
);
2710 else if (fileinfo
.st_uid
!= 0 ||
2711 (fileinfo
.st_mode
& MODE_WRITE
) ||
2712 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2714 if (!warn
&& !errors
&& !verbose
)
2715 _cupsLangPuts(stdout
, _(" FAIL"));
2718 _cupsLangPrintf(stdout
,
2719 _(" %s Bad permissions on %s file \"%s\"."),
2720 prefix
, "APDialogExtension", pathprog
);
2726 errors
= valid_path("APDialogExtension", pathprog
, errors
, verbose
,
2734 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2736 if (strcmp(attr
->name
, "APPrinterIconPath"))
2738 if (!warn
&& !errors
&& !verbose
)
2739 _cupsLangPuts(stdout
, _(" FAIL"));
2742 _cupsLangPrintf(stdout
,
2743 _(" %s Bad spelling of %s - should be %s."),
2744 prefix
, attr
->name
, "APPrinterIconPath");
2750 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2751 attr
->value
? attr
->value
: "(null)");
2753 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2755 if (!warn
&& !errors
&& !verbose
)
2756 _cupsLangPuts(stdout
, _(" FAIL"));
2759 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2760 prefix
, "APPrinterIconPath", pathprog
);
2765 else if (fileinfo
.st_uid
!= 0 ||
2766 (fileinfo
.st_mode
& MODE_WRITE
) ||
2767 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2769 if (!warn
&& !errors
&& !verbose
)
2770 _cupsLangPuts(stdout
, _(" FAIL"));
2773 _cupsLangPrintf(stdout
,
2774 _(" %s Bad permissions on %s file \"%s\"."),
2775 prefix
, "APPrinterIconPath", pathprog
);
2781 errors
= valid_path("APPrinterIconPath", pathprog
, errors
, verbose
,
2786 * APPrinterLowInkTool
2789 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2791 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2793 if (!warn
&& !errors
&& !verbose
)
2794 _cupsLangPuts(stdout
, _(" FAIL"));
2797 _cupsLangPrintf(stdout
,
2798 _(" %s Bad spelling of %s - should be %s."),
2799 prefix
, attr
->name
, "APPrinterLowInkTool");
2805 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2806 attr
->value
? attr
->value
: "(null)");
2808 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2810 if (!warn
&& !errors
&& !verbose
)
2811 _cupsLangPuts(stdout
, _(" FAIL"));
2814 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2815 prefix
, "APPrinterLowInkTool", pathprog
);
2820 else if (fileinfo
.st_uid
!= 0 ||
2821 (fileinfo
.st_mode
& MODE_WRITE
) ||
2822 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2824 if (!warn
&& !errors
&& !verbose
)
2825 _cupsLangPuts(stdout
, _(" FAIL"));
2828 _cupsLangPrintf(stdout
,
2829 _(" %s Bad permissions on %s file \"%s\"."),
2830 prefix
, "APPrinterLowInkTool", pathprog
);
2836 errors
= valid_path("APPrinterLowInkTool", pathprog
, errors
, verbose
,
2841 * APPrinterUtilityPath
2844 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2846 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2848 if (!warn
&& !errors
&& !verbose
)
2849 _cupsLangPuts(stdout
, _(" FAIL"));
2852 _cupsLangPrintf(stdout
,
2853 _(" %s Bad spelling of %s - should be %s."),
2854 prefix
, attr
->name
, "APPrinterUtilityPath");
2860 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2861 attr
->value
? attr
->value
: "(null)");
2863 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2865 if (!warn
&& !errors
&& !verbose
)
2866 _cupsLangPuts(stdout
, _(" FAIL"));
2869 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2870 prefix
, "APPrinterUtilityPath", pathprog
);
2875 else if (fileinfo
.st_uid
!= 0 ||
2876 (fileinfo
.st_mode
& MODE_WRITE
) ||
2877 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2879 if (!warn
&& !errors
&& !verbose
)
2880 _cupsLangPuts(stdout
, _(" FAIL"));
2883 _cupsLangPrintf(stdout
,
2884 _(" %s Bad permissions on %s file \"%s\"."),
2885 prefix
, "APPrinterUtilityPath", pathprog
);
2891 errors
= valid_path("APPrinterUtilityPath", pathprog
, errors
, verbose
,
2896 * APScanAppBundleID and APScanAppPath
2899 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2901 if (strcmp(attr
->name
, "APScanAppPath"))
2903 if (!warn
&& !errors
&& !verbose
)
2904 _cupsLangPuts(stdout
, _(" FAIL"));
2907 _cupsLangPrintf(stdout
,
2908 _(" %s Bad spelling of %s - should be %s."),
2909 prefix
, attr
->name
, "APScanAppPath");
2915 if (!attr
->value
|| stat(attr
->value
, &fileinfo
))
2917 if (!warn
&& !errors
&& !verbose
)
2918 _cupsLangPuts(stdout
, _(" FAIL"));
2921 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
2922 prefix
, "APScanAppPath",
2923 attr
->value
? attr
->value
: "<NULL>");
2928 else if (fileinfo
.st_uid
!= 0 ||
2929 (fileinfo
.st_mode
& MODE_WRITE
) ||
2930 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2932 if (!warn
&& !errors
&& !verbose
)
2933 _cupsLangPuts(stdout
, _(" FAIL"));
2936 _cupsLangPrintf(stdout
,
2937 _(" %s Bad permissions on %s file \"%s\"."),
2938 prefix
, "APScanAppPath", attr
->value
);
2944 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2947 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2949 if (!warn
&& !errors
&& !verbose
)
2950 _cupsLangPuts(stdout
, _(" FAIL"));
2953 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2954 "APScanAppPath and APScanAppBundleID."),
2961 #endif /* __APPLE__ */
2968 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2971 static int /* O - Errors found */
2972 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2973 const char *root
, /* I - Root directory */
2974 int errors
, /* I - Errors found */
2975 int verbose
, /* I - Verbosity level */
2976 int warn
) /* I - Warnings only? */
2978 int i
; /* Looping var */
2979 ppd_attr_t
*attr
; /* PPD attribute */
2980 const char *ptr
; /* Pointer into string */
2981 const char *prefix
; /* WARN/FAIL prefix */
2982 char filename
[1024]; /* Profile filename */
2983 struct stat fileinfo
; /* File information */
2984 int num_profiles
= 0; /* Number of profiles */
2985 unsigned hash
, /* Current hash value */
2986 hashes
[1000]; /* Hash values of profile names */
2987 const char *specs
[1000]; /* Specifiers for profiles */
2990 prefix
= warn
? " WARN " : "**FAIL**";
2992 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
2994 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
2997 * Check for valid selector...
3000 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
3003 if (!attr
->value
|| i
< 2)
3005 if (!warn
&& !errors
&& !verbose
)
3006 _cupsLangPuts(stdout
, _(" FAIL"));
3009 _cupsLangPrintf(stdout
,
3010 _(" %s Bad cupsICCProfile %s."),
3011 prefix
, attr
->spec
);
3020 * Check for valid profile filename...
3023 if (attr
->value
[0] == '/')
3024 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
3027 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
3030 if (*ptr
== '/' || !*root
)
3031 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
3034 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
3038 if (stat(filename
, &fileinfo
))
3040 if (!warn
&& !errors
&& !verbose
)
3041 _cupsLangPuts(stdout
, _(" FAIL"));
3044 _cupsLangPrintf(stdout
, _(" %s Missing %s file \"%s\"."),
3045 prefix
, "cupsICCProfile", filename
);
3050 else if (fileinfo
.st_uid
!= 0 ||
3051 (fileinfo
.st_mode
& MODE_WRITE
) ||
3052 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
3054 if (!warn
&& !errors
&& !verbose
)
3055 _cupsLangPuts(stdout
, _(" FAIL"));
3058 _cupsLangPrintf(stdout
,
3059 _(" %s Bad permissions on %s file \"%s\"."),
3060 prefix
, "cupsICCProfile", filename
);
3066 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
3069 * Check for hash collisions...
3072 hash
= _ppdHashName(attr
->spec
);
3074 if (num_profiles
> 0)
3076 for (i
= 0; i
< num_profiles
; i
++)
3077 if (hashes
[i
] == hash
)
3080 if (i
< num_profiles
)
3082 if (!warn
&& !errors
&& !verbose
)
3083 _cupsLangPuts(stdout
, _(" FAIL"));
3086 _cupsLangPrintf(stdout
,
3087 _(" %s cupsICCProfile %s hash value "
3088 "collides with %s."), prefix
, attr
->spec
,
3097 * Remember up to 1000 profiles...
3100 if (num_profiles
< 1000)
3102 hashes
[num_profiles
] = hash
;
3103 specs
[num_profiles
] = attr
->spec
;
3113 * 'check_sizes()' - Check media sizes in the PPD file.
3116 static int /* O - Errors found */
3117 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
3118 int errors
, /* I - Errors found */
3119 int verbose
, /* I - Verbosity level */
3120 int warn
) /* I - Warnings only? */
3122 int i
; /* Looping var */
3123 ppd_size_t
*size
; /* Current size */
3124 int width
, /* Custom width */
3125 length
; /* Custom length */
3126 const char *prefix
; /* WARN/FAIL prefix */
3127 ppd_option_t
*page_size
, /* PageSize option */
3128 *page_region
; /* PageRegion option */
3129 _pwg_media_t
*pwg_media
; /* PWG media */
3130 char buf
[PPD_MAX_NAME
]; /* PapeSize name that is supposed to be */
3131 const char *ptr
; /* Pointer into string */
3132 int width_2540ths
, /* PageSize width in 2540ths */
3133 length_2540ths
; /* PageSize length in 2540ths */
3134 int is_ok
; /* Flag for PageSize name verification */
3135 double width_tmp
, /* Width after rounded up */
3136 length_tmp
, /* Length after rounded up */
3137 width_inch
, /* Width in inches */
3138 length_inch
, /* Length in inches */
3139 width_mm
, /* Width in millimeters */
3140 length_mm
; /* Length in millimeters */
3143 prefix
= warn
? " WARN " : "**FAIL**";
3145 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
3147 if (!warn
&& !errors
&& !verbose
)
3148 _cupsLangPuts(stdout
, _(" FAIL"));
3151 _cupsLangPrintf(stdout
,
3152 _(" %s Missing REQUIRED PageSize option.\n"
3153 " REF: Page 99, section 5.14."),
3160 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
3162 if (!warn
&& !errors
&& !verbose
)
3163 _cupsLangPuts(stdout
, _(" FAIL"));
3166 _cupsLangPrintf(stdout
,
3167 _(" %s Missing REQUIRED PageRegion option.\n"
3168 " REF: Page 100, section 5.14."),
3175 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
3178 * Check that the size name is standard...
3181 if (!strcmp(size
->name
, "Custom"))
3184 * Skip custom page size...
3190 if (warn
!= 2 && size
->name
[0] == 'w' &&
3191 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
3194 * Validate device-specific size wNNNhNNN should have proper width and
3198 if (fabs(width
- size
->width
) >= 1.0 ||
3199 fabs(length
- size
->length
) >= 1.0)
3201 if (!warn
&& !errors
&& !verbose
)
3202 _cupsLangPuts(stdout
, _(" FAIL"));
3205 _cupsLangPrintf(stdout
,
3206 _(" %s Size \"%s\" has unexpected dimensions "
3208 prefix
, size
->name
, size
->width
, size
->length
);
3216 * Verify that the size is defined for both PageSize and PageRegion...
3219 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
3221 if (!warn
&& !errors
&& !verbose
)
3222 _cupsLangPuts(stdout
, _(" FAIL"));
3225 _cupsLangPrintf(stdout
,
3226 _(" %s Size \"%s\" defined for %s but not for "
3228 prefix
, size
->name
, "PageRegion", "PageSize");
3233 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3235 if (!warn
&& !errors
&& !verbose
)
3236 _cupsLangPuts(stdout
, _(" FAIL"));
3239 _cupsLangPrintf(stdout
,
3240 _(" %s Size \"%s\" defined for %s but not for "
3242 prefix
, size
->name
, "PageSize", "PageRegion");
3249 * Verify that the size name is Adobe standard name if it's a standard size
3250 * and the dimentional name if it's not a standard size. Suffix should be
3251 * .Fullbleed, etc., or numeric, e.g., Letter, Letter.Fullbleed,
3252 * Letter.Transverse, Letter1, Letter2, 4x8, 55x91mm, 55x91mm.Fullbleed, etc.
3258 width_2540ths
= (size
->length
> size
->width
) ?
3259 PWG_FROM_POINTS(size
->width
) :
3260 PWG_FROM_POINTS(size
->length
);
3261 length_2540ths
= (size
->length
> size
->width
) ?
3262 PWG_FROM_POINTS(size
->length
) :
3263 PWG_FROM_POINTS(size
->width
);
3264 pwg_media
= pwgMediaForSize(width_2540ths
, length_2540ths
);
3267 (abs(pwg_media
->width
- width_2540ths
) > 34 ||
3268 abs(pwg_media
->length
- length_2540ths
) > 34))
3269 pwg_media
= NULL
; /* Only flag matches within a point */
3271 if (pwg_media
&& pwg_media
->ppd
&&
3272 (pwg_media
->ppd
[0] < 'a' || pwg_media
->ppd
[0] > 'z'))
3274 size_t ppdlen
= strlen(pwg_media
->ppd
);
3275 /* Length of standard PPD name */
3277 strlcpy(buf
, pwg_media
->ppd
, sizeof(buf
));
3279 if (strcmp(size
->name
, buf
) && size
->width
> size
->length
)
3281 if (!strcmp(pwg_media
->ppd
, "DoublePostcardRotated"))
3282 strlcpy(buf
, "DoublePostcard", sizeof(buf
));
3283 else if (strstr(size
->name
, ".Transverse"))
3284 snprintf(buf
, sizeof(buf
), "%s.Transverse", pwg_media
->ppd
);
3286 snprintf(buf
, sizeof(buf
), "%sRotated", pwg_media
->ppd
);
3288 ppdlen
= strlen(buf
);
3291 if (size
->left
== 0 && size
->bottom
== 0 &&
3292 size
->right
== size
->width
&& size
->top
== size
->length
)
3294 strlcat(buf
, ".Fullbleed", sizeof(buf
) - strlen(buf
));
3295 if (_cups_strcasecmp(size
->name
, buf
))
3298 * Allow an additional qualifier such as ".WithTab"...
3301 size_t buflen
= strlen(buf
);/* Length of full bleed name */
3303 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3304 size
->name
[buflen
] != '.')
3308 else if (!strncmp(size
->name
, pwg_media
->ppd
, ppdlen
))
3311 * Check for a proper qualifier (number, "Small", or .something)...
3314 ptr
= size
->name
+ ppdlen
;
3316 if (isdigit(*ptr
& 255))
3318 for (ptr
++; *ptr
; ptr
++)
3320 if (!isdigit(*ptr
& 255))
3327 else if (*ptr
!= '.' && *ptr
&& strcmp(ptr
, "Small"))
3333 * Check for EnvSizeName as well...
3336 if (strncmp(pwg_media
->ppd
, "Env", 3) &&
3337 !strncmp(size
->name
, "Env", 3))
3338 snprintf(buf
, sizeof(buf
), "Env%s", pwg_media
->ppd
);
3340 if (strcmp(size
->name
, buf
))
3345 _cupsLangPrintf(stdout
,
3346 _(" %s Size \"%s\" should be the Adobe "
3347 "standard name \"%s\"."),
3348 prefix
, size
->name
, buf
);
3352 width_tmp
= (fabs(size
->width
- ceil(size
->width
)) < 0.1) ?
3353 ceil(size
->width
) : size
->width
;
3354 length_tmp
= (fabs(size
->length
- ceil(size
->length
)) < 0.1) ?
3355 ceil(size
->length
) : size
->length
;
3357 if (fmod(width_tmp
, 9.0) == 0.0 && fmod(length_tmp
, 9.0) == 0.0)
3359 width_inch
= width_tmp
/ 72.0;
3360 length_inch
= length_tmp
/ 72.0;
3362 snprintf(buf
, sizeof(buf
), "%gx%g", width_inch
, length_inch
);
3366 width_mm
= size
->width
/ 72.0 * 25.4;
3367 length_mm
= size
->length
/ 72.0 * 25.4;
3369 snprintf(buf
, sizeof(buf
), "%.0fx%.0fmm", width_mm
, length_mm
);
3372 if (size
->left
== 0 && size
->bottom
== 0 &&
3373 size
->right
== size
->width
&& size
->top
== size
->length
)
3374 strlcat(buf
, ".Fullbleed", sizeof(buf
));
3375 else if (size
->width
> size
->length
)
3376 strlcat(buf
, ".Transverse", sizeof(buf
));
3378 if (_cups_strcasecmp(size
->name
, buf
))
3380 size_t buflen
= strlen(buf
);
3381 /* Length of proposed name */
3383 if (_cups_strncasecmp(size
->name
, buf
, buflen
) ||
3384 (strcmp(size
->name
+ buflen
, "in") &&
3385 size
->name
[buflen
] != '.'))
3387 char altbuf
[PPD_MAX_NAME
];
3388 /* Alternate "wNNNhNNN" name */
3389 size_t altlen
; /* Length of alternate name */
3391 snprintf(altbuf
, sizeof(altbuf
), "w%.0fh%.0f", size
->width
,
3393 altlen
= strlen(altbuf
);
3394 if (_cups_strncasecmp(size
->name
, altbuf
, altlen
) ||
3395 (size
->name
[altlen
] && size
->name
[altlen
] != '.'))
3396 _cupsLangPrintf(stdout
,
3397 _(" %s Size \"%s\" should be \"%s\"."),
3398 prefix
, size
->name
, buf
);
3410 * 'check_translations()' - Check translations in the PPD file.
3413 static int /* O - Errors found */
3414 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3415 int errors
, /* I - Errors found */
3416 int verbose
, /* I - Verbosity level */
3417 int warn
) /* I - Warnings only? */
3419 int j
; /* Looping var */
3420 ppd_attr_t
*attr
; /* PPD attribute */
3421 cups_array_t
*languages
; /* Array of languages */
3422 int langlen
; /* Length of language */
3423 char *language
, /* Current language */
3424 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3425 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3426 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3427 cllkeyword
[PPD_MAX_NAME
];
3428 /* Custom option keyword (base) */
3429 ppd_option_t
*option
; /* Standard UI option */
3430 ppd_coption_t
*coption
; /* Custom option */
3431 ppd_cparam_t
*cparam
; /* Custom parameter */
3432 char ll
[3]; /* Base language */
3433 const char *prefix
; /* WARN/FAIL prefix */
3434 const char *text
; /* Pointer into UI text */
3437 prefix
= warn
? " WARN " : "**FAIL**";
3439 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3442 * This file contains localizations, check them...
3445 for (language
= (char *)cupsArrayFirst(languages
);
3447 language
= (char *)cupsArrayNext(languages
))
3449 langlen
= (int)strlen(language
);
3450 if (langlen
!= 2 && langlen
!= 5)
3452 if (!warn
&& !errors
&& !verbose
)
3453 _cupsLangPuts(stdout
, _(" FAIL"));
3456 _cupsLangPrintf(stdout
,
3457 _(" %s Bad language \"%s\"."),
3466 if (!strcmp(language
, "en"))
3469 strlcpy(ll
, language
, sizeof(ll
));
3472 * Loop through all options and choices...
3475 for (option
= ppdFirstOption(ppd
);
3477 option
= ppdNextOption(ppd
))
3479 if (!strcmp(option
->keyword
, "PageRegion"))
3482 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3483 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3485 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3486 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3488 if (!warn
&& !errors
&& !verbose
)
3489 _cupsLangPuts(stdout
, _(" FAIL"));
3492 _cupsLangPrintf(stdout
,
3493 _(" %s Missing \"%s\" translation "
3494 "string for option %s."),
3495 prefix
, language
, option
->keyword
);
3500 else if (!valid_utf8(attr
->text
))
3502 if (!warn
&& !errors
&& !verbose
)
3503 _cupsLangPuts(stdout
, _(" FAIL"));
3506 _cupsLangPrintf(stdout
,
3507 _(" %s Bad UTF-8 \"%s\" translation "
3508 "string for option %s."),
3509 prefix
, language
, option
->keyword
);
3515 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3517 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3520 for (j
= 0; j
< option
->num_choices
; j
++)
3523 * First see if this choice is a number; if so, don't require
3527 for (text
= option
->choices
[j
].text
; *text
; text
++)
3528 if (!strchr("0123456789-+.", *text
))
3535 * Check custom choices differently...
3538 if (!_cups_strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3539 (coption
= ppdFindCustomOption(ppd
,
3540 option
->keyword
)) != NULL
)
3542 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3543 language
, option
->keyword
);
3545 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3546 !valid_utf8(attr
->text
))
3548 if (!warn
&& !errors
&& !verbose
)
3549 _cupsLangPuts(stdout
, _(" FAIL"));
3552 _cupsLangPrintf(stdout
,
3553 _(" %s Bad UTF-8 \"%s\" "
3554 "translation string for option %s, "
3557 ckeyword
+ 1 + strlen(language
),
3564 if (_cups_strcasecmp(option
->keyword
, "PageSize"))
3566 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3568 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3570 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3571 language
, option
->keyword
);
3572 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3573 ll
, option
->keyword
);
3575 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3576 cparam
->name
)) == NULL
&&
3577 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3578 cparam
->name
)) == NULL
)
3580 if (!warn
&& !errors
&& !verbose
)
3581 _cupsLangPuts(stdout
, _(" FAIL"));
3584 _cupsLangPrintf(stdout
,
3585 _(" %s Missing \"%s\" "
3586 "translation string for option %s, "
3589 ckeyword
+ 1 + strlen(language
),
3595 else if (!valid_utf8(attr
->text
))
3597 if (!warn
&& !errors
&& !verbose
)
3598 _cupsLangPuts(stdout
, _(" FAIL"));
3601 _cupsLangPrintf(stdout
,
3602 _(" %s Bad UTF-8 \"%s\" "
3603 "translation string for option %s, "
3606 ckeyword
+ 1 + strlen(language
),
3615 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3616 option
->choices
[j
].choice
)) == NULL
&&
3617 (attr
= ppdFindAttr(ppd
, llkeyword
,
3618 option
->choices
[j
].choice
)) == NULL
)
3620 if (!warn
&& !errors
&& !verbose
)
3621 _cupsLangPuts(stdout
, _(" FAIL"));
3624 _cupsLangPrintf(stdout
,
3625 _(" %s Missing \"%s\" "
3626 "translation string for option %s, "
3628 prefix
, language
, option
->keyword
,
3629 option
->choices
[j
].choice
);
3634 else if (!valid_utf8(attr
->text
))
3636 if (!warn
&& !errors
&& !verbose
)
3637 _cupsLangPuts(stdout
, _(" FAIL"));
3640 _cupsLangPrintf(stdout
,
3641 _(" %s Bad UTF-8 \"%s\" "
3642 "translation string for option %s, "
3644 prefix
, language
, option
->keyword
,
3645 option
->choices
[j
].choice
);
3655 * Verify that we have the base language for each localized one...
3658 for (language
= (char *)cupsArrayFirst(languages
);
3660 language
= (char *)cupsArrayNext(languages
))
3664 * Lookup the base language...
3667 cupsArraySave(languages
);
3669 strlcpy(ll
, language
, sizeof(ll
));
3671 if (!cupsArrayFind(languages
, ll
) &&
3672 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3674 if (!warn
&& !errors
&& !verbose
)
3675 _cupsLangPuts(stdout
, _(" FAIL"));
3678 _cupsLangPrintf(stdout
,
3679 _(" %s No base translation \"%s\" "
3680 "is included in file."), prefix
, ll
);
3686 cupsArrayRestore(languages
);
3690 * Free memory used for the languages...
3693 _ppdFreeLanguages(languages
);
3701 * 'show_conflicts()' - Show option conflicts in a PPD file.
3705 show_conflicts(ppd_file_t
*ppd
, /* I - PPD to check */
3706 const char *prefix
) /* I - Prefix string */
3708 int i
, j
; /* Looping variables */
3709 ppd_const_t
*c
; /* Current constraint */
3710 ppd_option_t
*o1
, *o2
; /* Options */
3711 ppd_choice_t
*c1
, *c2
; /* Choices */
3715 * Loop through all of the UI constraints and report any options
3719 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3722 * Grab pointers to the first option...
3725 o1
= ppdFindOption(ppd
, c
->option1
);
3729 else if (c
->choice1
[0] != '\0')
3732 * This constraint maps to a specific choice.
3735 c1
= ppdFindChoice(o1
, c
->choice1
);
3740 * This constraint applies to any choice for this option.
3743 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3748 !_cups_strcasecmp(c1
->choice
, "None") ||
3749 !_cups_strcasecmp(c1
->choice
, "Off") ||
3750 !_cups_strcasecmp(c1
->choice
, "False"))
3755 * Grab pointers to the second option...
3758 o2
= ppdFindOption(ppd
, c
->option2
);
3762 else if (c
->choice2
[0] != '\0')
3765 * This constraint maps to a specific choice.
3768 c2
= ppdFindChoice(o2
, c
->choice2
);
3773 * This constraint applies to any choice for this option.
3776 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3781 !_cups_strcasecmp(c2
->choice
, "None") ||
3782 !_cups_strcasecmp(c2
->choice
, "Off") ||
3783 !_cups_strcasecmp(c2
->choice
, "False"))
3788 * If both options are marked then there is a conflict...
3791 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3792 _cupsLangPrintf(stdout
,
3793 _(" %s \"%s %s\" conflicts with \"%s %s\"\n"
3794 " (constraint=\"%s %s %s %s\")."),
3795 prefix
, o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3796 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3802 * 'test_raster()' - Test PostScript commands for raster printers.
3805 static int /* O - 1 on success, 0 on failure */
3806 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3807 int verbose
) /* I - Verbosity */
3809 cups_page_header2_t header
; /* Page header */
3812 ppdMarkDefaults(ppd
);
3813 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3816 _cupsLangPuts(stdout
, _(" FAIL"));
3819 _cupsLangPrintf(stdout
,
3820 _(" **FAIL** Default option code cannot be "
3821 "interpreted: %s"), cupsRasterErrorString());
3827 * Try a test of custom page size code, if available...
3830 if (!ppdPageSize(ppd
, "Custom.612x792"))
3833 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3835 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3838 _cupsLangPuts(stdout
, _(" FAIL"));
3841 _cupsLangPrintf(stdout
,
3842 _(" **FAIL** Default option code cannot be "
3843 "interpreted: %s"), cupsRasterErrorString());
3853 * 'usage()' - Show program usage.
3859 _cupsLangPuts(stdout
, _("Usage: cupstestppd [options] filename1.ppd[.gz] "
3860 "[... filenameN.ppd[.gz]]"));
3861 _cupsLangPuts(stdout
, _(" program | cupstestppd [options] -"));
3862 _cupsLangPuts(stdout
, "");
3863 _cupsLangPuts(stdout
, _("Options:"));
3864 _cupsLangPuts(stdout
, "");
3865 _cupsLangPuts(stdout
, _(" -I {filename,filters,none,profiles}"));
3866 _cupsLangPuts(stdout
, _(" Ignore specific warnings."));
3867 _cupsLangPuts(stdout
, _(" -R root-directory Set alternate root."));
3868 _cupsLangPuts(stdout
, _(" -W {all,none,constraints,defaults,duplex,"
3869 "filters,profiles,sizes,translations}"));
3870 _cupsLangPuts(stdout
, _(" Issue warnings instead of "
3872 _cupsLangPuts(stdout
, _(" -q Run silently."));
3873 _cupsLangPuts(stdout
, _(" -r Use 'relaxed' open mode."));
3874 _cupsLangPuts(stdout
, _(" -v Be verbose."));
3875 _cupsLangPuts(stdout
, _(" -vv Be very verbose."));
3882 * 'valid_path()' - Check whether a path has the correct capitalization.
3885 static int /* O - Errors found */
3886 valid_path(const char *keyword
, /* I - Keyword using path */
3887 const char *path
, /* I - Path to check */
3888 int errors
, /* I - Errors found */
3889 int verbose
, /* I - Verbosity level */
3890 int warn
) /* I - Warnings only? */
3892 cups_dir_t
*dir
; /* Current directory */
3893 cups_dentry_t
*dentry
; /* Current directory entry */
3894 char temp
[1024], /* Temporary path */
3895 *ptr
; /* Pointer into temporary path */
3896 const char *prefix
; /* WARN/FAIL prefix */
3899 prefix
= warn
? " WARN " : "**FAIL**";
3902 * Loop over the components of the path, checking that the entry exists with
3903 * the same capitalization...
3906 strlcpy(temp
, path
, sizeof(temp
));
3908 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3911 * Chop off the trailing component so temp == dirname and ptr == basename.
3917 * Try opening the directory containing the base name...
3921 dir
= cupsDirOpen(temp
);
3923 dir
= cupsDirOpen("/");
3929 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3931 if (!strcmp(dentry
->filename
, ptr
))
3939 * Display an error if the filename doesn't exist with the same
3945 if (!warn
&& !errors
&& !verbose
)
3946 _cupsLangPuts(stdout
, _(" FAIL"));
3949 _cupsLangPrintf(stdout
,
3950 _(" %s %s file \"%s\" has the wrong "
3951 "capitalization."), prefix
, keyword
, path
);
3965 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3968 static int /* O - 1 if valid, 0 if not */
3969 valid_utf8(const char *s
) /* I - String to check */
3976 * Check for valid UTF-8 sequence...
3979 if ((*s
& 0xc0) == 0x80)
3980 return (0); /* Illegal suffix byte */
3981 else if ((*s
& 0xe0) == 0xc0)
3984 * 2-byte sequence...
3989 if ((*s
& 0xc0) != 0x80)
3990 return (0); /* Missing suffix byte */
3992 else if ((*s
& 0xf0) == 0xe0)
3995 * 3-byte sequence...
4000 if ((*s
& 0xc0) != 0x80)
4001 return (0); /* Missing suffix byte */
4005 if ((*s
& 0xc0) != 0x80)
4006 return (0); /* Missing suffix byte */
4008 else if ((*s
& 0xf8) == 0xf0)
4011 * 4-byte sequence...
4016 if ((*s
& 0xc0) != 0x80)
4017 return (0); /* Missing suffix byte */
4021 if ((*s
& 0xc0) != 0x80)
4022 return (0); /* Missing suffix byte */
4026 if ((*s
& 0xc0) != 0x80)
4027 return (0); /* Missing suffix byte */
4030 return (0); /* Bad sequence */