2 * "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $"
4 * PPD test program for CUPS.
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * PostScript is a trademark of Adobe Systems, Inc.
17 * This file is subject to the Apple OS-Developed Software exception.
21 * main() - Main entry for test program.
22 * check_basics() - Check for CR LF, mixed line endings, and blank
24 * check_constraints() - Check UIConstraints in the PPD file.
25 * check_case() - Check that there are no duplicate groups, options,
26 * or choices that differ only by case.
27 * check_defaults() - Check default option keywords in the PPD file.
28 * check_duplex() - Check duplex keywords in the PPD file.
29 * check_filters() - Check filters in the PPD file.
30 * check_profiles() - Check ICC color profiles in the PPD file.
31 * check_sizes() - Check media sizes in the PPD file.
32 * check_translations() - Check translations in the PPD file.
33 * show_conflicts() - Show option conflicts in a PPD file.
34 * test_raster() - Test PostScript commands for raster printers.
35 * usage() - Show program usage...
36 * valid_path() - Check whether a path has the correct capitalization.
37 * valid_utf8() - Check whether a string contains valid UTF-8 text.
41 * Include necessary headers...
44 #include <cups/cups-private.h>
46 #include <cups/ppd-private.h>
47 #include <cups/raster.h>
55 * Error warning overrides...
65 WARN_TRANSLATIONS
= 16,
101 * File permissions...
104 #define MODE_WRITE 0022 /* Group/other write */
105 #define MODE_MASK 0555 /* Owner/group/other read+exec/search */
106 #define MODE_DATAFILE 0444 /* Owner/group/other read */
107 #define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
108 #define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
115 static void check_basics(const char *filename
);
116 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
118 static int check_case(ppd_file_t
*ppd
, int errors
, int verbose
);
119 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
121 static int check_duplex(ppd_file_t
*ppd
, int errors
, int verbose
,
123 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
124 int verbose
, int warn
);
125 static int check_profiles(ppd_file_t
*ppd
, const char *root
, int errors
,
126 int verbose
, int warn
);
127 static int check_sizes(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
128 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,
130 static void show_conflicts(ppd_file_t
*ppd
);
131 static int test_raster(ppd_file_t
*ppd
, int verbose
);
132 static void usage(void);
133 static int valid_path(const char *keyword
, const char *path
, int errors
,
134 int verbose
, int warn
);
135 static int valid_utf8(const char *s
);
139 * 'main()' - Main entry for test program.
142 int /* O - Exit status */
143 main(int argc
, /* I - Number of command-line args */
144 char *argv
[]) /* I - Command-line arguments */
146 int i
, j
, k
, m
, n
; /* Looping vars */
147 int len
; /* Length of option name */
148 char *opt
; /* Option character */
149 const char *ptr
; /* Pointer into string */
150 int files
; /* Number of files */
151 int verbose
; /* Want verbose output? */
152 int warn
; /* Which errors to just warn about */
153 int ignore
; /* Which errors to ignore */
154 int status
; /* Exit status */
155 int errors
; /* Number of conformance errors */
156 int ppdversion
; /* PPD spec version in PPD file */
157 ppd_status_t error
; /* Status of ppdOpen*() */
158 int line
; /* Line number for error */
159 char *root
; /* Root directory */
160 int xdpi
, /* X resolution */
161 ydpi
; /* Y resolution */
162 ppd_file_t
*ppd
; /* PPD file record */
163 ppd_attr_t
*attr
; /* PPD attribute */
164 ppd_size_t
*size
; /* Size record */
165 ppd_group_t
*group
; /* UI group */
166 ppd_option_t
*option
; /* Standard UI option */
167 ppd_group_t
*group2
; /* UI group */
168 ppd_option_t
*option2
; /* Standard UI option */
169 ppd_choice_t
*choice
; /* Standard UI option choice */
170 struct lconv
*loc
; /* Locale data */
171 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
172 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
173 "JCL", "PAGE", "PROLOG" };
176 _cupsSetLocale(argv
);
180 * Display PPD files for each file listed on the command-line...
183 ppdSetConformance(PPD_CONFORM_STRICT
);
193 for (i
= 1; i
< argc
; i
++)
194 if (argv
[i
][0] == '-' && argv
[i
][1])
196 for (opt
= argv
[i
] + 1; *opt
; opt
++)
199 case 'I' : /* Ignore errors */
205 if (!strcmp(argv
[i
], "none"))
207 else if (!strcmp(argv
[i
], "filename"))
208 ignore
|= WARN_FILENAME
;
209 else if (!strcmp(argv
[i
], "filters"))
210 ignore
|= WARN_FILTERS
;
211 else if (!strcmp(argv
[i
], "profiles"))
212 ignore
|= WARN_PROFILES
;
213 else if (!strcmp(argv
[i
], "all"))
214 ignore
= WARN_FILTERS
| WARN_PROFILES
;
219 case 'R' : /* Alternate root directory */
228 case 'W' : /* Turn errors into warnings */
234 if (!strcmp(argv
[i
], "none"))
236 else if (!strcmp(argv
[i
], "constraints"))
237 warn
|= WARN_CONSTRAINTS
;
238 else if (!strcmp(argv
[i
], "defaults"))
239 warn
|= WARN_DEFAULTS
;
240 else if (!strcmp(argv
[i
], "duplex"))
242 else if (!strcmp(argv
[i
], "filters"))
243 warn
|= WARN_FILTERS
;
244 else if (!strcmp(argv
[i
], "profiles"))
245 warn
|= WARN_PROFILES
;
246 else if (!strcmp(argv
[i
], "sizes"))
248 else if (!strcmp(argv
[i
], "translations"))
249 warn
|= WARN_TRANSLATIONS
;
250 else if (!strcmp(argv
[i
], "all"))
256 case 'q' : /* Quiet mode */
259 _cupsLangPuts(stderr
,
260 _("cupstestppd: The -q option is incompatible "
261 "with the -v option."));
268 case 'r' : /* Relaxed mode */
269 ppdSetConformance(PPD_CONFORM_RELAXED
);
272 case 'v' : /* Verbose mode */
275 _cupsLangPuts(stderr
,
276 _("cupstestppd: The -v option is incompatible "
277 "with the -q option."));
292 * Open the PPD file...
295 if (files
&& verbose
>= 0)
300 if (argv
[i
][0] == '-')
306 ppd
= ppdOpen(stdin
);
309 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
314 * Read from a file...
318 printf("%s:", argv
[i
]);
320 ppd
= ppdOpenFile(argv
[i
]);
325 error
= ppdLastError(&line
);
327 if (error
<= PPD_ALLOC_ERROR
)
329 status
= ERROR_FILE_OPEN
;
332 _cupsLangPrintf(stdout
,
334 " **FAIL** Unable to open PPD file - %s"),
339 status
= ERROR_PPD_FORMAT
;
343 _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 for (j
= 0; j
< ppd
->num_filters
; j
++)
441 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
443 if (!test_raster(ppd
, verbose
))
449 * Look for default keywords with no matching option...
452 if (!(warn
& WARN_DEFAULTS
))
453 errors
= check_defaults(ppd
, errors
, verbose
, 0);
455 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
459 if (!errors
&& !verbose
)
460 _cupsLangPuts(stdout
, _(" FAIL"));
462 _cupsLangPuts(stdout
,
463 _(" **FAIL** REQUIRED DefaultImageableArea\n"
464 " REF: Page 102, section 5.15."));
469 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
470 strcmp(attr
->value
, "Unknown"))
474 if (!errors
&& !verbose
)
475 _cupsLangPuts(stdout
, _(" FAIL"));
477 _cupsLangPrintf(stdout
,
478 _(" **FAIL** BAD DefaultImageableArea %s\n"
479 " REF: Page 102, section 5.15."),
488 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea"));
491 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
495 if (!errors
&& !verbose
)
496 _cupsLangPuts(stdout
, _(" FAIL"));
498 _cupsLangPuts(stdout
,
499 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
500 " REF: Page 103, section 5.15."));
505 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
506 strcmp(attr
->value
, "Unknown"))
510 if (!errors
&& !verbose
)
511 _cupsLangPuts(stdout
, _(" FAIL"));
513 _cupsLangPrintf(stdout
,
514 _(" **FAIL** BAD DefaultPaperDimension %s\n"
515 " REF: Page 103, section 5.15."),
521 else if (verbose
> 0)
522 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension"));
524 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
525 for (k
= 0, option
= group
->options
;
526 k
< group
->num_options
;
530 * Verify that we have a default choice...
533 if (option
->defchoice
[0])
535 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
536 strcmp(option
->defchoice
, "Unknown"))
540 if (!errors
&& !verbose
)
541 _cupsLangPuts(stdout
, _(" FAIL"));
543 _cupsLangPrintf(stdout
,
544 _(" **FAIL** BAD Default%s %s\n"
545 " REF: Page 40, section 4.5."),
546 option
->keyword
, option
->defchoice
);
551 else if (verbose
> 0)
552 _cupsLangPrintf(stdout
,
553 _(" PASS Default%s"),
560 if (!errors
&& !verbose
)
561 _cupsLangPuts(stdout
, _(" FAIL"));
563 _cupsLangPrintf(stdout
,
564 _(" **FAIL** REQUIRED Default%s\n"
565 " REF: Page 40, section 4.5."),
573 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
575 for (ptr
= attr
->value
; *ptr
; ptr
++)
576 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
583 if (!errors
&& !verbose
)
584 _cupsLangPuts(stdout
, _(" FAIL"));
586 _cupsLangPrintf(stdout
,
587 _(" **FAIL** Bad FileVersion \"%s\"\n"
588 " REF: Page 56, section 5.3."),
594 else if (verbose
> 0)
595 _cupsLangPuts(stdout
, _(" PASS FileVersion"));
601 if (!errors
&& !verbose
)
602 _cupsLangPuts(stdout
, _(" FAIL"));
604 _cupsLangPuts(stdout
,
605 _(" **FAIL** REQUIRED FileVersion\n"
606 " REF: Page 56, section 5.3."));
612 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
615 if (*ptr
== '4' && ptr
[1] == '.')
618 for (ptr
+= 2; *ptr
; ptr
++)
619 if (!isdigit(*ptr
& 255))
627 if (!errors
&& !verbose
)
628 _cupsLangPuts(stdout
, _(" FAIL"));
630 _cupsLangPrintf(stdout
,
631 _(" **FAIL** Bad FormatVersion \"%s\"\n"
632 " REF: Page 56, section 5.3."),
638 else if (verbose
> 0)
639 _cupsLangPuts(stdout
, _(" PASS FormatVersion"));
645 if (!errors
&& !verbose
)
646 _cupsLangPuts(stdout
, _(" FAIL"));
648 _cupsLangPuts(stdout
,
649 _(" **FAIL** REQUIRED FormatVersion\n"
650 " REF: Page 56, section 5.3."));
656 if (ppd
->lang_encoding
!= NULL
)
659 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding"));
661 else if (ppdversion
> 40)
665 if (!errors
&& !verbose
)
666 _cupsLangPuts(stdout
, _(" FAIL"));
668 _cupsLangPuts(stdout
,
669 _(" **FAIL** REQUIRED LanguageEncoding\n"
670 " REF: Pages 56-57, section 5.3."));
676 if (ppd
->lang_version
!= NULL
)
679 _cupsLangPuts(stdout
, _(" PASS LanguageVersion"));
685 if (!errors
&& !verbose
)
686 _cupsLangPuts(stdout
, _(" FAIL"));
688 _cupsLangPuts(stdout
,
689 _(" **FAIL** REQUIRED LanguageVersion\n"
690 " REF: Pages 57-58, section 5.3."));
696 if (ppd
->manufacturer
!= NULL
)
698 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
699 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
703 if (!errors
&& !verbose
)
704 _cupsLangPuts(stdout
, _(" FAIL"));
706 _cupsLangPuts(stdout
,
707 _(" **FAIL** BAD Manufacturer (should be "
709 " REF: Page 211, table D.1."));
714 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
715 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
719 if (!errors
&& !verbose
)
720 _cupsLangPuts(stdout
, _(" FAIL"));
722 _cupsLangPuts(stdout
,
723 _(" **FAIL** BAD Manufacturer (should be "
725 " REF: Page 211, table D.1."));
730 else if (verbose
> 0)
731 _cupsLangPuts(stdout
, _(" PASS Manufacturer"));
733 else if (ppdversion
>= 43)
737 if (!errors
&& !verbose
)
738 _cupsLangPuts(stdout
, _(" FAIL"));
740 _cupsLangPuts(stdout
,
741 _(" **FAIL** REQUIRED Manufacturer\n"
742 " REF: Pages 58-59, section 5.3."));
748 if (ppd
->modelname
!= NULL
)
750 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
751 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
758 if (!errors
&& !verbose
)
759 _cupsLangPuts(stdout
, _(" FAIL"));
761 _cupsLangPrintf(stdout
,
762 _(" **FAIL** BAD ModelName - \"%c\" not "
763 "allowed in string.\n"
764 " REF: Pages 59-60, section 5.3."),
770 else if (verbose
> 0)
771 _cupsLangPuts(stdout
, _(" PASS ModelName"));
777 if (!errors
&& !verbose
)
778 _cupsLangPuts(stdout
, _(" FAIL"));
780 _cupsLangPuts(stdout
,
781 _(" **FAIL** REQUIRED ModelName\n"
782 " REF: Pages 59-60, section 5.3."));
788 if (ppd
->nickname
!= NULL
)
791 _cupsLangPuts(stdout
, _(" PASS NickName"));
797 if (!errors
&& !verbose
)
798 _cupsLangPuts(stdout
, _(" FAIL"));
800 _cupsLangPuts(stdout
,
801 _(" **FAIL** REQUIRED NickName\n"
802 " REF: Page 60, section 5.3."));
808 if (ppdFindOption(ppd
, "PageSize") != NULL
)
811 _cupsLangPuts(stdout
, _(" PASS PageSize"));
817 if (!errors
&& !verbose
)
818 _cupsLangPuts(stdout
, _(" FAIL"));
820 _cupsLangPuts(stdout
,
821 _(" **FAIL** REQUIRED PageSize\n"
822 " REF: Pages 99-100, section 5.14."));
828 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
831 _cupsLangPuts(stdout
, _(" PASS PageRegion"));
837 if (!errors
&& !verbose
)
838 _cupsLangPuts(stdout
, _(" FAIL"));
840 _cupsLangPuts(stdout
,
841 _(" **FAIL** REQUIRED PageRegion\n"
842 " REF: Page 100, section 5.14."));
848 if (ppd
->pcfilename
!= NULL
)
851 _cupsLangPuts(stdout
, _(" PASS PCFileName"));
853 else if (!(ignore
& WARN_FILENAME
))
857 if (!errors
&& !verbose
)
858 _cupsLangPuts(stdout
, _(" FAIL"));
860 _cupsLangPuts(stdout
,
861 _(" **FAIL** REQUIRED PCFileName\n"
862 " REF: Pages 61-62, section 5.3."));
868 if (ppd
->product
!= NULL
)
870 if (ppd
->product
[0] != '(' ||
871 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
875 if (!errors
&& !verbose
)
876 _cupsLangPuts(stdout
, _(" FAIL"));
878 _cupsLangPuts(stdout
,
879 _(" **FAIL** BAD Product - not \"(string)\".\n"
880 " REF: Page 62, section 5.3."));
885 else if (verbose
> 0)
886 _cupsLangPuts(stdout
, _(" PASS Product"));
892 if (!errors
&& !verbose
)
893 _cupsLangPuts(stdout
, _(" FAIL"));
895 _cupsLangPuts(stdout
,
896 _(" **FAIL** REQUIRED Product\n"
897 " REF: Page 62, section 5.3."));
903 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
906 char junkstr
[255]; /* Temp string */
907 int junkint
; /* Temp integer */
910 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
914 if (!errors
&& !verbose
)
915 _cupsLangPuts(stdout
, _(" FAIL"));
917 _cupsLangPuts(stdout
,
918 _(" **FAIL** BAD PSVersion - not \"(string) "
920 " REF: Pages 62-64, section 5.3."));
925 else if (verbose
> 0)
926 _cupsLangPuts(stdout
, _(" PASS PSVersion"));
932 if (!errors
&& !verbose
)
933 _cupsLangPuts(stdout
, _(" FAIL"));
935 _cupsLangPuts(stdout
,
936 _(" **FAIL** REQUIRED PSVersion\n"
937 " REF: Pages 62-64, section 5.3."));
943 if (ppd
->shortnickname
!= NULL
)
945 if (strlen(ppd
->shortnickname
) > 31)
949 if (!errors
&& !verbose
)
950 _cupsLangPuts(stdout
, _(" FAIL"));
952 _cupsLangPuts(stdout
,
953 _(" **FAIL** BAD ShortNickName - longer "
955 " REF: Pages 64-65, section 5.3."));
960 else if (verbose
> 0)
961 _cupsLangPuts(stdout
, _(" PASS ShortNickName"));
963 else if (ppdversion
>= 43)
967 if (!errors
&& !verbose
)
968 _cupsLangPuts(stdout
, _(" FAIL"));
970 _cupsLangPuts(stdout
,
971 _(" **FAIL** REQUIRED ShortNickName\n"
972 " REF: Page 64-65, section 5.3."));
978 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
979 strstr(ppd
->patches
, "*End"))
983 if (!errors
&& !verbose
)
984 _cupsLangPuts(stdout
, _(" FAIL"));
986 _cupsLangPuts(stdout
,
987 _(" **FAIL** BAD JobPatchFile attribute in file\n"
988 " REF: Page 24, section 3.4."));
995 * Check for page sizes without the corresponding ImageableArea or
996 * PaperDimension values...
999 if (ppd
->num_sizes
== 0)
1003 if (!errors
&& !verbose
)
1004 _cupsLangPuts(stdout
, _(" FAIL"));
1006 _cupsLangPuts(stdout
,
1007 _(" **FAIL** REQUIRED PageSize\n"
1008 " REF: Page 41, section 5.\n"
1009 " REF: Page 99, section 5.14."));
1016 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1019 * Don't check custom size...
1022 if (!strcmp(size
->name
, "Custom"))
1026 * Check for ImageableArea...
1029 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1030 size
->right
== 0.0 && size
->top
== 0.0)
1034 if (!errors
&& !verbose
)
1035 _cupsLangPuts(stdout
, _(" FAIL"));
1037 _cupsLangPrintf(stdout
,
1038 _(" **FAIL** REQUIRED ImageableArea for "
1040 " REF: Page 41, section 5.\n"
1041 " REF: Page 102, section 5.15."),
1049 * Check for PaperDimension...
1052 if (size
->width
== 0.0 && size
->length
== 0.0)
1056 if (!errors
&& !verbose
)
1057 _cupsLangPuts(stdout
, _(" FAIL"));
1059 _cupsLangPrintf(stdout
,
1060 _(" **FAIL** REQUIRED PaperDimension "
1062 " REF: Page 41, section 5.\n"
1063 " REF: Page 103, section 5.15."),
1073 * Check for valid Resolution, JCLResolution, or SetResolution values...
1076 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1077 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1078 option
= ppdFindOption(ppd
, "SetResolution");
1082 for (j
= option
->num_choices
, choice
= option
->choices
;
1087 * Verify that all resolution options are of the form NNNdpi
1091 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1092 if (ptr
> choice
->choice
&& xdpi
> 0)
1095 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1102 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1107 if (!errors
&& !verbose
)
1108 _cupsLangPuts(stdout
, _(" FAIL"));
1110 _cupsLangPrintf(stdout
,
1111 _(" **FAIL** Bad %s choice %s\n"
1112 " REF: Page 84, section 5.9"),
1113 option
->keyword
, choice
->choice
);
1121 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1122 strcmp(attr
->name
, "1284DeviceID"))
1126 if (!errors
&& !verbose
)
1127 _cupsLangPuts(stdout
, _(" FAIL"));
1129 _cupsLangPrintf(stdout
,
1130 _(" **FAIL** %s must be 1284DeviceID\n"
1131 " REF: Page 72, section 5.5"),
1138 errors
= check_case(ppd
, errors
, verbose
);
1140 if (!(warn
& WARN_CONSTRAINTS
))
1141 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1143 if (!(warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1144 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1146 if (!(warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1147 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1149 if (!(warn
& WARN_SIZES
))
1150 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1152 if (!(warn
& WARN_TRANSLATIONS
))
1153 errors
= check_translations(ppd
, errors
, verbose
, 0);
1155 if (!(warn
& WARN_DUPLEX
))
1156 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1158 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1162 * This file contains localizations, check for conformance of the
1163 * base translation...
1166 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1168 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1170 if (!errors
&& !verbose
)
1171 _cupsLangPuts(stdout
, _(" FAIL"));
1174 _cupsLangPrintf(stdout
,
1175 _(" **FAIL** Bad LanguageEncoding %s - "
1176 "must be ISOLatin1."),
1177 attr
->value
? attr
->value
: "(null)");
1182 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1184 if (!errors
&& !verbose
)
1185 _cupsLangPuts(stdout
, _(" FAIL"));
1188 _cupsLangPrintf(stdout
,
1189 _(" **FAIL** Bad LanguageVersion %s - "
1190 "must be English."),
1191 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1197 * Loop through all options and choices...
1200 for (option
= ppdFirstOption(ppd
);
1202 option
= ppdNextOption(ppd
))
1205 * Check for special characters outside A0 to BF, F7, or F8
1206 * that are used for languages other than English.
1209 for (ptr
= option
->text
; *ptr
; ptr
++)
1210 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1211 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1216 if (!errors
&& !verbose
)
1217 _cupsLangPuts(stdout
, _(" FAIL"));
1220 _cupsLangPrintf(stdout
,
1221 _(" **FAIL** Default translation "
1222 "string for option %s contains 8-bit "
1229 for (j
= 0; j
< option
->num_choices
; j
++)
1232 * Check for special characters outside A0 to BF, F7, or F8
1233 * that are used for languages other than English.
1236 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1237 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1238 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1243 if (!errors
&& !verbose
)
1244 _cupsLangPuts(stdout
, _(" FAIL"));
1247 _cupsLangPrintf(stdout
,
1248 _(" **FAIL** Default translation "
1249 "string for option %s choice %s contains "
1250 "8-bit characters."),
1252 option
->choices
[j
].choice
);
1262 * Final pass/fail notification...
1266 status
= ERROR_CONFORMANCE
;
1268 _cupsLangPuts(stdout
, _(" PASS"));
1272 check_basics(argv
[i
]);
1274 if (warn
& WARN_DEFAULTS
)
1275 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1277 if (warn
& WARN_CONSTRAINTS
)
1278 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1280 if ((warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1281 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1283 if ((warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1284 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1286 if (warn
& WARN_SIZES
)
1287 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1289 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1291 if (warn
& WARN_TRANSLATIONS
)
1292 errors
= check_translations(ppd
, errors
, verbose
, 1);
1294 if (warn
& WARN_DUPLEX
)
1295 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1298 * Look for legacy duplex keywords...
1301 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1302 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1303 option
= ppdFindOption(ppd
, "KD03Duplex");
1306 _cupsLangPrintf(stdout
,
1307 _(" WARN Duplex option keyword %s may not "
1308 "work as expected and should be named Duplex.\n"
1309 " REF: Page 122, section 5.17"),
1313 * Look for default keywords with no corresponding option...
1316 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1318 attr
= ppd
->attrs
[j
];
1320 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1321 !strcmp(attr
->name
, "DefaultColorSep") ||
1322 !strcmp(attr
->name
, "DefaultFont") ||
1323 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1324 !strcmp(attr
->name
, "DefaultImageableArea") ||
1325 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1326 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1327 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1328 !strcmp(attr
->name
, "DefaultResolution") ||
1329 !strcmp(attr
->name
, "DefaultScreenProc") ||
1330 !strcmp(attr
->name
, "DefaultTransfer"))
1333 if (!strncmp(attr
->name
, "Default", 7) &&
1334 !ppdFindOption(ppd
, attr
->name
+ 7))
1335 _cupsLangPrintf(stdout
,
1336 _(" WARN %s has no corresponding "
1341 ppdMarkDefaults(ppd
);
1342 if (ppdConflicts(ppd
))
1344 _cupsLangPuts(stdout
,
1345 _(" WARN Default choices conflicting."));
1347 show_conflicts(ppd
);
1350 if (ppdversion
< 43)
1352 _cupsLangPrintf(stdout
,
1353 _(" WARN Obsolete PPD version %.1f.\n"
1354 " REF: Page 42, section 5.2."),
1358 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1360 _cupsLangPuts(stdout
,
1361 _(" WARN LanguageEncoding required by PPD "
1363 " REF: Pages 56-57, section 5.3."));
1366 if (!ppd
->manufacturer
&& ppdversion
< 43)
1368 _cupsLangPuts(stdout
,
1369 _(" WARN Manufacturer required by PPD "
1371 " REF: Pages 58-59, section 5.3."));
1375 * Treat a PCFileName attribute longer than 12 characters as
1376 * a warning and not a hard error...
1379 if (!(ignore
& WARN_FILENAME
) && ppd
->pcfilename
)
1381 if (strlen(ppd
->pcfilename
) > 12)
1383 _cupsLangPuts(stdout
,
1384 _(" WARN PCFileName longer than 8.3 in "
1385 "violation of PPD spec.\n"
1386 " REF: Pages 61-62, section "
1390 if (!strcasecmp(ppd
->pcfilename
, "unused.ppd"))
1391 _cupsLangPuts(stdout
,
1392 _(" WARN PCFileName should contain a "
1393 "unique filename.\n"
1394 " REF: Pages 61-62, section "
1398 if (!ppd
->shortnickname
&& ppdversion
< 43)
1400 _cupsLangPuts(stdout
,
1401 _(" WARN ShortNickName required by PPD "
1403 " REF: Pages 64-65, section 5.3."));
1407 * Check the Protocols line and flag PJL + BCP since TBCP is
1408 * usually used with PJL...
1413 if (strstr(ppd
->protocols
, "PJL") &&
1414 strstr(ppd
->protocols
, "BCP") &&
1415 !strstr(ppd
->protocols
, "TBCP"))
1417 _cupsLangPuts(stdout
,
1418 _(" WARN Protocols contains both PJL "
1419 "and BCP; expected TBCP.\n"
1420 " REF: Pages 78-79, section 5.7."));
1423 if (strstr(ppd
->protocols
, "PJL") &&
1424 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1426 _cupsLangPuts(stdout
,
1427 _(" WARN Protocols contains PJL but JCL "
1428 "attributes are not set.\n"
1429 " REF: Pages 78-79, section 5.7."));
1434 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1435 * which are errors according to the spec but won't cause problems
1436 * with CUPS specifically...
1439 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1440 for (k
= 0, option
= group
->options
;
1441 k
< group
->num_options
;
1444 len
= (int)strlen(option
->keyword
);
1446 for (m
= 0, group2
= ppd
->groups
;
1447 m
< ppd
->num_groups
;
1449 for (n
= 0, option2
= group2
->options
;
1450 n
< group2
->num_options
;
1452 if (option
!= option2
&&
1453 len
< (int)strlen(option2
->keyword
) &&
1454 !strncmp(option
->keyword
, option2
->keyword
, len
))
1456 _cupsLangPrintf(stdout
,
1457 _(" WARN %s shares a common "
1459 " REF: Page 15, section "
1461 option
->keyword
, option2
->keyword
);
1469 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND"), errors
);
1471 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND"));
1475 * Then list the options, if "-v" was provided...
1480 _cupsLangPrintf(stdout
,
1482 " language_level = %d\n"
1483 " color_device = %s\n"
1484 " variable_sizes = %s\n"
1486 ppd
->language_level
,
1487 ppd
->color_device
? "TRUE" : "FALSE",
1488 ppd
->variable_sizes
? "TRUE" : "FALSE",
1491 switch (ppd
->colorspace
)
1494 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK");
1497 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY");
1500 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY");
1503 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB");
1506 _cupsLangPuts(stdout
, " colorspace = <unknown>");
1510 _cupsLangPrintf(stdout
, " num_emulations = %d",
1511 ppd
->num_emulations
);
1512 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1513 _cupsLangPrintf(stdout
, " emulations[%d] = %s",
1514 j
, ppd
->emulations
[j
].name
);
1516 _cupsLangPrintf(stdout
, " lang_encoding = %s",
1517 ppd
->lang_encoding
);
1518 _cupsLangPrintf(stdout
, " lang_version = %s",
1520 _cupsLangPrintf(stdout
, " modelname = %s", ppd
->modelname
);
1521 _cupsLangPrintf(stdout
, " ttrasterizer = %s",
1522 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1523 _cupsLangPrintf(stdout
, " manufacturer = %s",
1525 _cupsLangPrintf(stdout
, " product = %s", ppd
->product
);
1526 _cupsLangPrintf(stdout
, " nickname = %s", ppd
->nickname
);
1527 _cupsLangPrintf(stdout
, " shortnickname = %s",
1528 ppd
->shortnickname
);
1529 _cupsLangPrintf(stdout
, " patches = %d bytes",
1530 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1532 _cupsLangPrintf(stdout
, " num_groups = %d", ppd
->num_groups
);
1533 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1535 _cupsLangPrintf(stdout
, " group[%d] = %s",
1538 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1540 _cupsLangPrintf(stdout
,
1541 " options[%d] = %s (%s) %s %s %.0f "
1543 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1544 sections
[option
->section
], option
->order
,
1545 option
->num_choices
);
1547 if (!strcmp(option
->keyword
, "PageSize") ||
1548 !strcmp(option
->keyword
, "PageRegion"))
1550 for (m
= option
->num_choices
, choice
= option
->choices
;
1554 size
= ppdPageSize(ppd
, choice
->choice
);
1557 _cupsLangPrintf(stdout
,
1558 " %s (%s) = ERROR%s",
1559 choice
->choice
, choice
->text
,
1560 !strcmp(option
->defchoice
, choice
->choice
)
1563 _cupsLangPrintf(stdout
,
1564 " %s (%s) = %.2fx%.2fin "
1565 "(%.1f,%.1f,%.1f,%.1f)%s",
1566 choice
->choice
, choice
->text
,
1567 size
->width
/ 72.0, size
->length
/ 72.0,
1568 size
->left
/ 72.0, size
->bottom
/ 72.0,
1569 size
->right
/ 72.0, size
->top
/ 72.0,
1570 !strcmp(option
->defchoice
, choice
->choice
)
1576 for (m
= option
->num_choices
, choice
= option
->choices
;
1580 _cupsLangPrintf(stdout
, " %s (%s)%s",
1581 choice
->choice
, choice
->text
,
1582 !strcmp(option
->defchoice
, choice
->choice
)
1589 _cupsLangPrintf(stdout
, " num_consts = %d",
1591 for (j
= 0; j
< ppd
->num_consts
; j
++)
1592 _cupsLangPrintf(stdout
,
1593 " consts[%d] = *%s %s *%s %s",
1594 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1595 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1597 _cupsLangPrintf(stdout
, " num_profiles = %d",
1599 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1600 _cupsLangPrintf(stdout
,
1601 " profiles[%d] = %s/%s %.3f %.3f "
1602 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]",
1603 j
, ppd
->profiles
[j
].resolution
,
1604 ppd
->profiles
[j
].media_type
,
1605 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1606 ppd
->profiles
[j
].matrix
[0][0],
1607 ppd
->profiles
[j
].matrix
[0][1],
1608 ppd
->profiles
[j
].matrix
[0][2],
1609 ppd
->profiles
[j
].matrix
[1][0],
1610 ppd
->profiles
[j
].matrix
[1][1],
1611 ppd
->profiles
[j
].matrix
[1][2],
1612 ppd
->profiles
[j
].matrix
[2][0],
1613 ppd
->profiles
[j
].matrix
[2][1],
1614 ppd
->profiles
[j
].matrix
[2][2]);
1616 _cupsLangPrintf(stdout
, " num_fonts = %d", ppd
->num_fonts
);
1617 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1618 _cupsLangPrintf(stdout
, " fonts[%d] = %s",
1621 _cupsLangPrintf(stdout
, " num_attrs = %d", ppd
->num_attrs
);
1622 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1623 _cupsLangPrintf(stdout
,
1624 " attrs[%d] = %s %s%s%s: \"%s\"", j
,
1625 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1626 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1627 ppd
->attrs
[j
]->text
,
1628 ppd
->attrs
[j
]->value
?
1629 ppd
->attrs
[j
]->value
: "(null)");
1643 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1647 check_basics(const char *filename
) /* I - PPD file to check */
1649 cups_file_t
*fp
; /* File pointer */
1650 int ch
; /* Current character */
1651 int col
, /* Current column */
1652 whitespace
; /* Only seen whitespace? */
1653 int eol
; /* Line endings */
1654 int linenum
; /* Line number */
1655 int mixed
; /* Mixed line endings? */
1658 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1667 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1669 if (ch
== '\r' || ch
== '\n')
1673 if (eol
== EOL_NONE
)
1675 else if (eol
!= EOL_LF
)
1678 else if (ch
== '\r')
1680 if (cupsFilePeekChar(fp
) == '\n')
1682 cupsFileGetChar(fp
);
1684 if (eol
== EOL_NONE
)
1686 else if (eol
!= EOL_CRLF
)
1689 else if (eol
== EOL_NONE
)
1691 else if (eol
!= EOL_CR
)
1695 if (col
> 0 && whitespace
)
1696 _cupsLangPrintf(stdout
,
1697 _(" WARN Line %d only contains whitespace."),
1706 if (ch
!= ' ' && ch
!= '\t')
1714 _cupsLangPuts(stdout
,
1715 _(" WARN File contains a mix of CR, LF, and "
1716 "CR LF line endings."));
1718 if (eol
== EOL_CRLF
)
1719 _cupsLangPuts(stdout
,
1720 _(" WARN Non-Windows PPD files should use lines "
1721 "ending with only LF, not CR LF."));
1728 * 'check_constraints()' - Check UIConstraints in the PPD file.
1731 static int /* O - Errors found */
1732 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1733 int errors
, /* I - Errors found */
1734 int verbose
, /* I - Verbosity level */
1735 int warn
) /* I - Warnings only? */
1737 int i
; /* Looping var */
1738 const char *prefix
; /* WARN/FAIL prefix */
1739 ppd_const_t
*c
; /* Current UIConstraints data */
1740 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1741 const char *vptr
; /* Pointer into constraint value */
1742 char option
[PPD_MAX_NAME
],
1743 /* Option name/MainKeyword */
1744 choice
[PPD_MAX_NAME
],
1745 /* Choice/OptionKeyword */
1746 *ptr
; /* Pointer into option or choice */
1747 int num_options
; /* Number of options */
1748 cups_option_t
*options
; /* Options */
1749 ppd_option_t
*o
; /* PPD option */
1752 prefix
= warn
? " WARN " : "**FAIL**";
1756 * See what kind of constraint data we have in the PPD...
1759 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1762 * Check new-style cupsUIConstraints data...
1766 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1768 if (!constattr
->value
)
1770 if (!warn
&& !errors
&& !verbose
)
1771 _cupsLangPuts(stdout
, _(" FAIL"));
1773 _cupsLangPrintf(stdout
,
1774 _(" %s Empty cupsUIConstraints %s"),
1775 prefix
, constattr
->spec
);
1783 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1785 i
++, vptr
= strchr(vptr
+ 1, '*'));
1789 if (!warn
&& !errors
&& !verbose
)
1790 _cupsLangPuts(stdout
, _(" FAIL"));
1792 _cupsLangPrintf(stdout
,
1793 _(" %s Bad cupsUIConstraints %s: \"%s\""),
1794 prefix
, constattr
->spec
, constattr
->value
);
1802 cupsArraySave(ppd
->sorted_attrs
);
1804 if (constattr
->spec
[0] &&
1805 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1807 if (!warn
&& !errors
&& !verbose
)
1808 _cupsLangPuts(stdout
, _(" FAIL"));
1810 _cupsLangPrintf(stdout
,
1811 _(" %s Missing cupsUIResolver %s"),
1812 prefix
, constattr
->spec
);
1818 cupsArrayRestore(ppd
->sorted_attrs
);
1823 for (vptr
= strchr(constattr
->value
, '*');
1825 vptr
= strchr(vptr
, '*'))
1828 * Extract "*Option Choice" or just "*Option"...
1831 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1832 if (ptr
< (option
+ sizeof(option
) - 1))
1837 while (isspace(*vptr
& 255))
1844 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1845 if (ptr
< (choice
+ sizeof(choice
) - 1))
1851 if (!strncasecmp(option
, "Custom", 6) && !strcasecmp(choice
, "True"))
1853 _cups_strcpy(option
, option
+ 6);
1854 strcpy(choice
, "Custom");
1857 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1859 if (!warn
&& !errors
&& !verbose
)
1860 _cupsLangPuts(stdout
, _(" FAIL"));
1862 _cupsLangPrintf(stdout
,
1863 _(" %s Missing option %s in "
1864 "cupsUIConstraints %s: \"%s\""),
1865 prefix
, option
, constattr
->spec
, constattr
->value
);
1873 if (choice
[0] && !ppdFindChoice(o
, choice
))
1875 if (!warn
&& !errors
&& !verbose
)
1876 _cupsLangPuts(stdout
, _(" FAIL"));
1878 _cupsLangPrintf(stdout
,
1879 _(" %s Missing choice *%s %s in "
1880 "cupsUIConstraints %s: \"%s\""),
1881 prefix
, option
, choice
, constattr
->spec
,
1891 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1894 for (i
= 0; i
< o
->num_choices
; i
++)
1895 if (strcasecmp(o
->choices
[i
].choice
, "None") &&
1896 strcasecmp(o
->choices
[i
].choice
, "Off") &&
1897 strcasecmp(o
->choices
[i
].choice
, "False"))
1899 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
1900 num_options
, &options
);
1907 * Resolvers must list at least two options...
1910 if (num_options
< 2)
1912 if (!warn
&& !errors
&& !verbose
)
1913 _cupsLangPuts(stdout
, _(" FAIL"));
1915 _cupsLangPrintf(stdout
,
1916 _(" %s cupsUIResolver %s does not list at least "
1917 "two different options."),
1918 prefix
, constattr
->spec
);
1925 * Test the resolver...
1928 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
1930 if (!warn
&& !errors
&& !verbose
)
1931 _cupsLangPuts(stdout
, _(" FAIL"));
1933 _cupsLangPrintf(stdout
,
1934 _(" %s cupsUIResolver %s causes a loop."),
1935 prefix
, constattr
->spec
);
1941 cupsFreeOptions(num_options
, options
);
1947 * Check old-style [Non]UIConstraints data...
1950 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1952 if (!strncasecmp(c
->option1
, "Custom", 6) &&
1953 !strcasecmp(c
->choice1
, "True"))
1955 strcpy(option
, c
->option1
+ 6);
1956 strcpy(choice
, "Custom");
1960 strcpy(option
, c
->option1
);
1961 strcpy(choice
, c
->choice1
);
1964 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1966 if (!warn
&& !errors
&& !verbose
)
1967 _cupsLangPuts(stdout
, _(" FAIL"));
1969 _cupsLangPrintf(stdout
,
1970 _(" %s Missing option %s in "
1971 "UIConstraints \"*%s %s *%s %s\"."),
1973 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1978 else if (choice
[0] && !ppdFindChoice(o
, choice
))
1980 if (!warn
&& !errors
&& !verbose
)
1981 _cupsLangPuts(stdout
, _(" FAIL"));
1983 _cupsLangPrintf(stdout
,
1984 _(" %s Missing choice *%s %s in "
1985 "UIConstraints \"*%s %s *%s %s\"."),
1986 prefix
, c
->option1
, c
->choice1
,
1987 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1993 if (!strncasecmp(c
->option2
, "Custom", 6) &&
1994 !strcasecmp(c
->choice2
, "True"))
1996 strcpy(option
, c
->option2
+ 6);
1997 strcpy(choice
, "Custom");
2001 strcpy(option
, c
->option2
);
2002 strcpy(choice
, c
->choice2
);
2005 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
2007 if (!warn
&& !errors
&& !verbose
)
2008 _cupsLangPuts(stdout
, _(" FAIL"));
2010 _cupsLangPrintf(stdout
,
2011 _(" %s Missing option %s in "
2012 "UIConstraints \"*%s %s *%s %s\"."),
2014 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2019 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2021 if (!warn
&& !errors
&& !verbose
)
2022 _cupsLangPuts(stdout
, _(" FAIL"));
2024 _cupsLangPrintf(stdout
,
2025 _(" %s Missing choice *%s %s in "
2026 "UIConstraints \"*%s %s *%s %s\"."),
2027 prefix
, c
->option2
, c
->choice2
,
2028 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2041 * 'check_case()' - Check that there are no duplicate groups, options,
2042 * or choices that differ only by case.
2045 static int /* O - Errors found */
2046 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2047 int errors
, /* I - Errors found */
2048 int verbose
) /* I - Verbosity level */
2050 int i
, j
; /* Looping vars */
2051 ppd_group_t
*groupa
, /* First group */
2052 *groupb
; /* Second group */
2053 ppd_option_t
*optiona
, /* First option */
2054 *optionb
; /* Second option */
2055 ppd_choice_t
*choicea
, /* First choice */
2056 *choiceb
; /* Second choice */
2060 * Check that the groups do not have any duplicate names...
2063 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2064 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2065 if (!strcasecmp(groupa
->name
, groupb
->name
))
2067 if (!errors
&& !verbose
)
2068 _cupsLangPuts(stdout
, _(" FAIL"));
2071 _cupsLangPrintf(stdout
,
2072 _(" **FAIL** Group names %s and %s differ only "
2074 groupa
->name
, groupb
->name
);
2080 * Check that the options do not have any duplicate names...
2083 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2085 cupsArraySave(ppd
->options
);
2086 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2087 if (!strcasecmp(optiona
->keyword
, optionb
->keyword
))
2089 if (!errors
&& !verbose
)
2090 _cupsLangPuts(stdout
, _(" FAIL"));
2093 _cupsLangPrintf(stdout
,
2094 _(" **FAIL** Option names %s and %s differ only "
2096 optiona
->keyword
, optionb
->keyword
);
2100 cupsArrayRestore(ppd
->options
);
2103 * Then the choices...
2106 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2109 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2110 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2112 if (!errors
&& !verbose
)
2113 _cupsLangPuts(stdout
, _(" FAIL"));
2116 _cupsLangPrintf(stdout
,
2117 _(" **FAIL** Multiple occurrences of %s "
2119 optiona
->keyword
, choicea
->choice
);
2127 else if (!strcasecmp(choicea
->choice
, choiceb
->choice
))
2129 if (!errors
&& !verbose
)
2130 _cupsLangPuts(stdout
, _(" FAIL"));
2133 _cupsLangPrintf(stdout
,
2134 _(" **FAIL** %s choice names %s and %s "
2135 "differ only by case."),
2136 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2143 * Return the number of errors found...
2151 * 'check_defaults()' - Check default option keywords in the PPD file.
2154 static int /* O - Errors found */
2155 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2156 int errors
, /* I - Errors found */
2157 int verbose
, /* I - Verbosity level */
2158 int warn
) /* I - Warnings only? */
2160 int j
, k
; /* Looping vars */
2161 ppd_attr_t
*attr
; /* PPD attribute */
2162 ppd_option_t
*option
; /* Standard UI option */
2163 const char *prefix
; /* WARN/FAIL prefix */
2166 prefix
= warn
? " WARN " : "**FAIL**";
2168 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2170 attr
= ppd
->attrs
[j
];
2172 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2173 !strcmp(attr
->name
, "DefaultFont") ||
2174 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2175 !strcmp(attr
->name
, "DefaultImageableArea") ||
2176 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2177 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2178 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2179 !strcmp(attr
->name
, "DefaultResolution") ||
2180 !strcmp(attr
->name
, "DefaultTransfer"))
2183 if (!strncmp(attr
->name
, "Default", 7))
2185 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2186 strcmp(attr
->value
, "Unknown"))
2189 * Check that the default option value matches a choice...
2192 for (k
= 0; k
< option
->num_choices
; k
++)
2193 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2196 if (k
>= option
->num_choices
)
2198 if (!warn
&& !errors
&& !verbose
)
2199 _cupsLangPuts(stdout
, _(" FAIL"));
2202 _cupsLangPrintf(stdout
,
2203 _(" %s %s %s does not exist."),
2204 prefix
, attr
->name
, attr
->value
);
2218 * 'check_duplex()' - Check duplex keywords in the PPD file.
2221 static int /* O - Errors found */
2222 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2223 int errors
, /* I - Error found */
2224 int verbose
, /* I - Verbosity level */
2225 int warn
) /* I - Warnings only? */
2227 int i
; /* Looping var */
2228 ppd_option_t
*option
; /* PPD option */
2229 ppd_choice_t
*choice
; /* Current choice */
2230 const char *prefix
; /* Message prefix */
2233 prefix
= warn
? " WARN " : "**FAIL**";
2236 * Check for a duplex option, and for standard values...
2239 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2241 if (!ppdFindChoice(option
, "None"))
2245 if (!warn
&& !errors
&& !verbose
)
2246 _cupsLangPuts(stdout
, _(" FAIL"));
2248 _cupsLangPrintf(stdout
,
2249 _(" %s REQUIRED %s does not define "
2251 " REF: Page 122, section 5.17"),
2252 prefix
, option
->keyword
);
2259 for (i
= option
->num_choices
, choice
= option
->choices
;
2262 if (strcmp(choice
->choice
, "None") &&
2263 strcmp(choice
->choice
, "DuplexNoTumble") &&
2264 strcmp(choice
->choice
, "DuplexTumble") &&
2265 strcmp(choice
->choice
, "SimplexTumble"))
2269 if (!warn
&& !errors
&& !verbose
)
2270 _cupsLangPuts(stdout
, _(" FAIL"));
2272 _cupsLangPrintf(stdout
,
2273 _(" %s Bad %s choice %s.\n"
2274 " REF: Page 122, section 5.17"),
2275 prefix
, option
->keyword
, choice
->choice
);
2288 * 'check_filters()' - Check filters in the PPD file.
2291 static int /* O - Errors found */
2292 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2293 const char *root
, /* I - Root directory */
2294 int errors
, /* I - Errors found */
2295 int verbose
, /* I - Verbosity level */
2296 int warn
) /* I - Warnings only? */
2298 int i
; /* Looping var */
2299 ppd_attr_t
*attr
; /* PPD attribute */
2300 const char *ptr
; /* Pointer into string */
2301 char super
[16], /* Super-type for filter */
2302 type
[256], /* Type for filter */
2303 program
[1024], /* Program/filter name */
2304 pathprog
[1024]; /* Complete path to program/filter */
2305 int cost
; /* Cost of filter */
2306 const char *prefix
; /* WARN/FAIL prefix */
2307 struct stat fileinfo
; /* File information */
2310 prefix
= warn
? " WARN " : "**FAIL**";
2316 for (i
= 0; i
< ppd
->num_filters
; i
++)
2318 if (sscanf(ppd
->filters
[i
], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2319 &cost
, program
) != 4)
2321 if (!warn
&& !errors
&& !verbose
)
2322 _cupsLangPuts(stdout
, _(" FAIL"));
2325 _cupsLangPrintf(stdout
,
2326 _(" %s Bad cupsFilter value \"%s\"."),
2327 prefix
, ppd
->filters
[i
]);
2332 else if (strcmp(program
, "-"))
2334 if (program
[0] == '/')
2335 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2338 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2339 ptr
= CUPS_SERVERBIN
;
2341 if (*ptr
== '/' || !*root
)
2342 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2345 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2349 if (stat(pathprog
, &fileinfo
))
2351 if (!warn
&& !errors
&& !verbose
)
2352 _cupsLangPuts(stdout
, _(" FAIL"));
2355 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
2356 "file \"%s\"."), prefix
, pathprog
);
2361 else if (fileinfo
.st_uid
!= 0 ||
2362 (fileinfo
.st_mode
& MODE_WRITE
) ||
2363 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2365 if (!warn
&& !errors
&& !verbose
)
2366 _cupsLangPuts(stdout
, _(" FAIL"));
2369 _cupsLangPrintf(stdout
, _(" %s Bad permissions on cupsFilter "
2370 "file \"%s\"."), prefix
, pathprog
);
2376 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2384 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2386 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2388 if (strcmp(attr
->name
, "cupsPreFilter"))
2390 if (!warn
&& !errors
&& !verbose
)
2391 _cupsLangPuts(stdout
, _(" FAIL"));
2394 _cupsLangPrintf(stdout
,
2395 _(" %s Bad spelling of %s - should be %s."),
2396 prefix
, attr
->name
, "cupsPreFilter");
2403 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2404 &cost
, program
) != 4)
2406 if (!warn
&& !errors
&& !verbose
)
2407 _cupsLangPuts(stdout
, _(" FAIL"));
2410 _cupsLangPrintf(stdout
,
2411 _(" %s Bad cupsPreFilter value \"%s\"."),
2412 prefix
, attr
->value
? attr
->value
: "");
2417 else if (strcmp(program
, "-"))
2419 if (program
[0] == '/')
2420 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2423 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2424 ptr
= CUPS_SERVERBIN
;
2426 if (*ptr
== '/' || !*root
)
2427 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2430 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2434 if (stat(pathprog
, &fileinfo
))
2436 if (!warn
&& !errors
&& !verbose
)
2437 _cupsLangPuts(stdout
, _(" FAIL"));
2440 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
2441 "file \"%s\"."), prefix
, pathprog
);
2446 else if (fileinfo
.st_uid
!= 0 ||
2447 (fileinfo
.st_mode
& MODE_WRITE
) ||
2448 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2450 if (!warn
&& !errors
&& !verbose
)
2451 _cupsLangPuts(stdout
, _(" FAIL"));
2454 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2455 "cupsPreFilter file \"%s\"."), prefix
,
2462 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2471 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2473 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2475 if (strcmp(attr
->name
, "APDialogExtension"))
2477 if (!warn
&& !errors
&& !verbose
)
2478 _cupsLangPuts(stdout
, _(" FAIL"));
2481 _cupsLangPrintf(stdout
,
2482 _(" %s Bad spelling of %s - should be %s."),
2483 prefix
, attr
->name
, "APDialogExtension");
2489 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2490 attr
->value
? attr
->value
: "(null)");
2492 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2494 if (!warn
&& !errors
&& !verbose
)
2495 _cupsLangPuts(stdout
, _(" FAIL"));
2498 _cupsLangPrintf(stdout
, _(" %s Missing "
2499 "APDialogExtension file \"%s\"."),
2505 else if (fileinfo
.st_uid
!= 0 ||
2506 (fileinfo
.st_mode
& MODE_WRITE
) ||
2507 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2509 if (!warn
&& !errors
&& !verbose
)
2510 _cupsLangPuts(stdout
, _(" FAIL"));
2513 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2514 "APDialogExtension file \"%s\"."), prefix
,
2521 errors
= valid_path("APDialogExtension", pathprog
, errors
, verbose
,
2529 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2531 if (strcmp(attr
->name
, "APPrinterIconPath"))
2533 if (!warn
&& !errors
&& !verbose
)
2534 _cupsLangPuts(stdout
, _(" FAIL"));
2537 _cupsLangPrintf(stdout
,
2538 _(" %s Bad spelling of %s - should be %s."),
2539 prefix
, attr
->name
, "APPrinterIconPath");
2545 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2546 attr
->value
? attr
->value
: "(null)");
2548 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2550 if (!warn
&& !errors
&& !verbose
)
2551 _cupsLangPuts(stdout
, _(" FAIL"));
2554 _cupsLangPrintf(stdout
, _(" %s Missing "
2555 "APPrinterIconPath file \"%s\"."),
2561 else if (fileinfo
.st_uid
!= 0 ||
2562 (fileinfo
.st_mode
& MODE_WRITE
) ||
2563 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2565 if (!warn
&& !errors
&& !verbose
)
2566 _cupsLangPuts(stdout
, _(" FAIL"));
2569 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2570 "APPrinterIconPath file \"%s\"."), prefix
,
2577 errors
= valid_path("APPrinterIconPath", pathprog
, errors
, verbose
,
2582 * APPrinterLowInkTool
2585 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2587 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2589 if (!warn
&& !errors
&& !verbose
)
2590 _cupsLangPuts(stdout
, _(" FAIL"));
2593 _cupsLangPrintf(stdout
,
2594 _(" %s Bad spelling of %s - should be %s."),
2595 prefix
, attr
->name
, "APPrinterLowInkTool");
2601 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2602 attr
->value
? attr
->value
: "(null)");
2604 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2606 if (!warn
&& !errors
&& !verbose
)
2607 _cupsLangPuts(stdout
, _(" FAIL"));
2610 _cupsLangPrintf(stdout
, _(" %s Missing "
2611 "APPrinterLowInkTool file \"%s\"."),
2617 else if (fileinfo
.st_uid
!= 0 ||
2618 (fileinfo
.st_mode
& MODE_WRITE
) ||
2619 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2621 if (!warn
&& !errors
&& !verbose
)
2622 _cupsLangPuts(stdout
, _(" FAIL"));
2625 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2626 "APPrinterLowInkTool file \"%s\"."), prefix
,
2633 errors
= valid_path("APPrinterLowInkTool", pathprog
, errors
, verbose
,
2638 * APPrinterUtilityPath
2641 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2643 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2645 if (!warn
&& !errors
&& !verbose
)
2646 _cupsLangPuts(stdout
, _(" FAIL"));
2649 _cupsLangPrintf(stdout
,
2650 _(" %s Bad spelling of %s - should be %s."),
2651 prefix
, attr
->name
, "APPrinterUtilityPath");
2657 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2658 attr
->value
? attr
->value
: "(null)");
2660 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2662 if (!warn
&& !errors
&& !verbose
)
2663 _cupsLangPuts(stdout
, _(" FAIL"));
2666 _cupsLangPrintf(stdout
, _(" %s Missing "
2667 "APPrinterUtilityPath file \"%s\"."),
2673 else if (fileinfo
.st_uid
!= 0 ||
2674 (fileinfo
.st_mode
& MODE_WRITE
) ||
2675 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2677 if (!warn
&& !errors
&& !verbose
)
2678 _cupsLangPuts(stdout
, _(" FAIL"));
2681 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2682 "APPrinterUtilityPath file \"%s\"."), prefix
,
2689 errors
= valid_path("APPrinterUtilityPath", pathprog
, errors
, verbose
,
2694 * APScanAppBundleID and APScanAppPath
2697 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2699 if (strcmp(attr
->name
, "APScanAppPath"))
2701 if (!warn
&& !errors
&& !verbose
)
2702 _cupsLangPuts(stdout
, _(" FAIL"));
2705 _cupsLangPrintf(stdout
,
2706 _(" %s Bad spelling of %s - should be %s."),
2707 prefix
, attr
->name
, "APScanAppPath");
2713 if (!attr
->value
|| stat(attr
->value
, &fileinfo
))
2715 if (!warn
&& !errors
&& !verbose
)
2716 _cupsLangPuts(stdout
, _(" FAIL"));
2719 _cupsLangPrintf(stdout
, _(" %s Missing "
2720 "APScanAppPath file \"%s\"."),
2721 prefix
, attr
->value
? attr
->value
: "<NULL>");
2726 else if (fileinfo
.st_uid
!= 0 ||
2727 (fileinfo
.st_mode
& MODE_WRITE
) ||
2728 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2730 if (!warn
&& !errors
&& !verbose
)
2731 _cupsLangPuts(stdout
, _(" FAIL"));
2734 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2735 "APScanAppPath file \"%s\"."), prefix
,
2742 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2745 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2747 if (!warn
&& !errors
&& !verbose
)
2748 _cupsLangPuts(stdout
, _(" FAIL"));
2751 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2752 "APScanAppPath and APScanAppBundleID."),
2759 #endif /* __APPLE__ */
2766 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2769 static int /* O - Errors found */
2770 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2771 const char *root
, /* I - Root directory */
2772 int errors
, /* I - Errors found */
2773 int verbose
, /* I - Verbosity level */
2774 int warn
) /* I - Warnings only? */
2776 int i
; /* Looping var */
2777 ppd_attr_t
*attr
; /* PPD attribute */
2778 const char *ptr
; /* Pointer into string */
2779 const char *prefix
; /* WARN/FAIL prefix */
2780 char filename
[1024]; /* Profile filename */
2781 struct stat fileinfo
; /* File information */
2782 int num_profiles
= 0; /* Number of profiles */
2783 unsigned hash
, /* Current hash value */
2784 hashes
[1000]; /* Hash values of profile names */
2785 const char *specs
[1000]; /* Specifiers for profiles */
2788 prefix
= warn
? " WARN " : "**FAIL**";
2790 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
2792 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
2795 * Check for valid selector...
2798 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
2801 if (!attr
->value
|| i
< 2)
2803 if (!warn
&& !errors
&& !verbose
)
2804 _cupsLangPuts(stdout
, _(" FAIL"));
2807 _cupsLangPrintf(stdout
,
2808 _(" %s Bad cupsICCProfile %s."),
2809 prefix
, attr
->spec
);
2818 * Check for valid profile filename...
2821 if (attr
->value
[0] == '/')
2822 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
2825 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
2828 if (*ptr
== '/' || !*root
)
2829 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
2832 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
2836 if (stat(filename
, &fileinfo
))
2838 if (!warn
&& !errors
&& !verbose
)
2839 _cupsLangPuts(stdout
, _(" FAIL"));
2842 _cupsLangPrintf(stdout
, _(" %s Missing cupsICCProfile "
2843 "file \"%s\"."), prefix
, filename
);
2848 else if (fileinfo
.st_uid
!= 0 ||
2849 (fileinfo
.st_mode
& MODE_WRITE
) ||
2850 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2852 if (!warn
&& !errors
&& !verbose
)
2853 _cupsLangPuts(stdout
, _(" FAIL"));
2856 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2857 "cupsICCProfile file \"%s\"."), prefix
,
2864 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
2867 * Check for hash collisions...
2870 hash
= _ppdHashName(attr
->spec
);
2872 if (num_profiles
> 0)
2874 for (i
= 0; i
< num_profiles
; i
++)
2875 if (hashes
[i
] == hash
)
2878 if (i
< num_profiles
)
2880 if (!warn
&& !errors
&& !verbose
)
2881 _cupsLangPuts(stdout
, _(" FAIL"));
2884 _cupsLangPrintf(stdout
,
2885 _(" %s cupsICCProfile %s hash value "
2886 "collides with %s."), prefix
, attr
->spec
,
2895 * Remember up to 1000 profiles...
2898 if (num_profiles
< 1000)
2900 hashes
[num_profiles
] = hash
;
2901 specs
[num_profiles
] = attr
->spec
;
2911 * 'check_sizes()' - Check media sizes in the PPD file.
2914 static int /* O - Errors found */
2915 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
2916 int errors
, /* I - Errors found */
2917 int verbose
, /* I - Verbosity level */
2918 int warn
) /* I - Warnings only? */
2920 int i
; /* Looping vars */
2921 ppd_size_t
*size
; /* Current size */
2922 int width
, /* Custom width */
2923 length
; /* Custom length */
2924 const char *prefix
; /* WARN/FAIL prefix */
2925 ppd_option_t
*page_size
, /* PageSize option */
2926 *page_region
; /* PageRegion option */
2929 prefix
= warn
? " WARN " : "**FAIL**";
2931 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
2933 if (!warn
&& !errors
&& !verbose
)
2934 _cupsLangPuts(stdout
, _(" FAIL"));
2937 _cupsLangPrintf(stdout
,
2938 _(" %s Missing REQUIRED PageSize option.\n"
2939 " REF: Page 99, section 5.14."),
2946 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
2948 if (!warn
&& !errors
&& !verbose
)
2949 _cupsLangPuts(stdout
, _(" FAIL"));
2952 _cupsLangPrintf(stdout
,
2953 _(" %s Missing REQUIRED PageRegion option.\n"
2954 " REF: Page 100, section 5.14."),
2961 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
2964 * Check that the size name is standard...
2967 if (!strcmp(size
->name
, "Custom"))
2970 * Skip custom page size...
2975 else if (warn
!= 2 && size
->name
[0] == 'w' &&
2976 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
2979 * Validate device-specific size wNNNhNNN should have proper width and
2983 if (fabs(width
- size
->width
) >= 1.0 ||
2984 fabs(length
- size
->length
) >= 1.0)
2986 if (!warn
&& !errors
&& !verbose
)
2987 _cupsLangPuts(stdout
, _(" FAIL"));
2990 _cupsLangPrintf(stdout
,
2991 _(" %s Size \"%s\" has unexpected dimensions "
2993 prefix
, size
->name
, size
->width
, size
->length
);
3001 * Verify that the size is defined for both PageSize and PageRegion...
3004 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
3006 if (!warn
&& !errors
&& !verbose
)
3007 _cupsLangPuts(stdout
, _(" FAIL"));
3010 _cupsLangPrintf(stdout
,
3011 _(" %s Size \"%s\" defined for %s but not for "
3013 prefix
, size
->name
, "PageRegion", "PageSize");
3018 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3020 if (!warn
&& !errors
&& !verbose
)
3021 _cupsLangPuts(stdout
, _(" FAIL"));
3024 _cupsLangPrintf(stdout
,
3025 _(" %s Size \"%s\" defined for %s but not for "
3027 prefix
, size
->name
, "PageSize", "PageRegion");
3039 * 'check_translations()' - Check translations in the PPD file.
3042 static int /* O - Errors found */
3043 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3044 int errors
, /* I - Errors found */
3045 int verbose
, /* I - Verbosity level */
3046 int warn
) /* I - Warnings only? */
3048 int j
; /* Looping var */
3049 ppd_attr_t
*attr
; /* PPD attribute */
3050 cups_array_t
*languages
; /* Array of languages */
3051 int langlen
; /* Length of language */
3052 char *language
, /* Current language */
3053 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3054 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3055 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3056 cllkeyword
[PPD_MAX_NAME
];
3057 /* Custom option keyword (base) */
3058 ppd_option_t
*option
; /* Standard UI option */
3059 ppd_coption_t
*coption
; /* Custom option */
3060 ppd_cparam_t
*cparam
; /* Custom parameter */
3061 char ll
[3]; /* Base language */
3062 const char *prefix
; /* WARN/FAIL prefix */
3063 const char *text
; /* Pointer into UI text */
3066 prefix
= warn
? " WARN " : "**FAIL**";
3068 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3071 * This file contains localizations, check them...
3074 for (language
= (char *)cupsArrayFirst(languages
);
3076 language
= (char *)cupsArrayNext(languages
))
3078 langlen
= (int)strlen(language
);
3079 if (langlen
!= 2 && langlen
!= 5)
3081 if (!warn
&& !errors
&& !verbose
)
3082 _cupsLangPuts(stdout
, _(" FAIL"));
3085 _cupsLangPrintf(stdout
,
3086 _(" %s Bad language \"%s\"."),
3095 if (!strcmp(language
, "en"))
3098 strlcpy(ll
, language
, sizeof(ll
));
3101 * Loop through all options and choices...
3104 for (option
= ppdFirstOption(ppd
);
3106 option
= ppdNextOption(ppd
))
3108 if (!strcmp(option
->keyword
, "PageRegion"))
3111 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3112 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3114 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3115 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3117 if (!warn
&& !errors
&& !verbose
)
3118 _cupsLangPuts(stdout
, _(" FAIL"));
3121 _cupsLangPrintf(stdout
,
3122 _(" %s Missing \"%s\" translation "
3123 "string for option %s."),
3124 prefix
, language
, option
->keyword
);
3129 else if (!valid_utf8(attr
->text
))
3131 if (!warn
&& !errors
&& !verbose
)
3132 _cupsLangPuts(stdout
, _(" FAIL"));
3135 _cupsLangPrintf(stdout
,
3136 _(" %s Bad UTF-8 \"%s\" translation "
3137 "string for option %s."),
3138 prefix
, language
, option
->keyword
);
3144 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3146 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3149 for (j
= 0; j
< option
->num_choices
; j
++)
3152 * First see if this choice is a number; if so, don't require
3156 for (text
= option
->choices
[j
].text
; *text
; text
++)
3157 if (!strchr("0123456789-+.", *text
))
3164 * Check custom choices differently...
3167 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3168 (coption
= ppdFindCustomOption(ppd
,
3169 option
->keyword
)) != NULL
)
3171 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3172 language
, option
->keyword
);
3174 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3175 !valid_utf8(attr
->text
))
3177 if (!warn
&& !errors
&& !verbose
)
3178 _cupsLangPuts(stdout
, _(" FAIL"));
3181 _cupsLangPrintf(stdout
,
3182 _(" %s Bad UTF-8 \"%s\" "
3183 "translation string for option %s, "
3186 ckeyword
+ 1 + strlen(language
),
3193 if (strcasecmp(option
->keyword
, "PageSize"))
3195 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3197 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3199 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3200 language
, option
->keyword
);
3201 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3202 ll
, option
->keyword
);
3204 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3205 cparam
->name
)) == NULL
&&
3206 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3207 cparam
->name
)) == NULL
)
3209 if (!warn
&& !errors
&& !verbose
)
3210 _cupsLangPuts(stdout
, _(" FAIL"));
3213 _cupsLangPrintf(stdout
,
3214 _(" %s Missing \"%s\" "
3215 "translation string for option %s, "
3218 ckeyword
+ 1 + strlen(language
),
3224 else if (!valid_utf8(attr
->text
))
3226 if (!warn
&& !errors
&& !verbose
)
3227 _cupsLangPuts(stdout
, _(" FAIL"));
3230 _cupsLangPrintf(stdout
,
3231 _(" %s Bad UTF-8 \"%s\" "
3232 "translation string for option %s, "
3235 ckeyword
+ 1 + strlen(language
),
3244 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3245 option
->choices
[j
].choice
)) == NULL
&&
3246 (attr
= ppdFindAttr(ppd
, llkeyword
,
3247 option
->choices
[j
].choice
)) == NULL
)
3249 if (!warn
&& !errors
&& !verbose
)
3250 _cupsLangPuts(stdout
, _(" FAIL"));
3253 _cupsLangPrintf(stdout
,
3254 _(" %s Missing \"%s\" "
3255 "translation string for option %s, "
3257 prefix
, language
, option
->keyword
,
3258 option
->choices
[j
].choice
);
3263 else if (!valid_utf8(attr
->text
))
3265 if (!warn
&& !errors
&& !verbose
)
3266 _cupsLangPuts(stdout
, _(" FAIL"));
3269 _cupsLangPrintf(stdout
,
3270 _(" %s Bad UTF-8 \"%s\" "
3271 "translation string for option %s, "
3273 prefix
, language
, option
->keyword
,
3274 option
->choices
[j
].choice
);
3284 * Verify that we have the base language for each localized one...
3287 for (language
= (char *)cupsArrayFirst(languages
);
3289 language
= (char *)cupsArrayNext(languages
))
3293 * Lookup the base language...
3296 cupsArraySave(languages
);
3298 strlcpy(ll
, language
, sizeof(ll
));
3300 if (!cupsArrayFind(languages
, ll
) &&
3301 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3303 if (!warn
&& !errors
&& !verbose
)
3304 _cupsLangPuts(stdout
, _(" FAIL"));
3307 _cupsLangPrintf(stdout
,
3308 _(" %s No base translation \"%s\" "
3309 "is included in file."), prefix
, ll
);
3315 cupsArrayRestore(languages
);
3319 * Free memory used for the languages...
3322 _ppdFreeLanguages(languages
);
3330 * 'show_conflicts()' - Show option conflicts in a PPD file.
3334 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
3336 int i
, j
; /* Looping variables */
3337 ppd_const_t
*c
; /* Current constraint */
3338 ppd_option_t
*o1
, *o2
; /* Options */
3339 ppd_choice_t
*c1
, *c2
; /* Choices */
3343 * Loop through all of the UI constraints and report any options
3347 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3350 * Grab pointers to the first option...
3353 o1
= ppdFindOption(ppd
, c
->option1
);
3357 else if (c
->choice1
[0] != '\0')
3360 * This constraint maps to a specific choice.
3363 c1
= ppdFindChoice(o1
, c
->choice1
);
3368 * This constraint applies to any choice for this option.
3371 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3376 !strcasecmp(c1
->choice
, "None") ||
3377 !strcasecmp(c1
->choice
, "Off") ||
3378 !strcasecmp(c1
->choice
, "False"))
3383 * Grab pointers to the second option...
3386 o2
= ppdFindOption(ppd
, c
->option2
);
3390 else if (c
->choice2
[0] != '\0')
3393 * This constraint maps to a specific choice.
3396 c2
= ppdFindChoice(o2
, c
->choice2
);
3401 * This constraint applies to any choice for this option.
3404 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3409 !strcasecmp(c2
->choice
, "None") ||
3410 !strcasecmp(c2
->choice
, "Off") ||
3411 !strcasecmp(c2
->choice
, "False"))
3416 * If both options are marked then there is a conflict...
3419 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3420 _cupsLangPrintf(stdout
,
3421 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
3422 " (constraint=\"%s %s %s %s\")."),
3423 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3424 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3430 * 'test_raster()' - Test PostScript commands for raster printers.
3433 static int /* O - 1 on success, 0 on failure */
3434 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3435 int verbose
) /* I - Verbosity */
3437 cups_page_header2_t header
; /* Page header */
3440 ppdMarkDefaults(ppd
);
3441 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3444 _cupsLangPuts(stdout
, _(" FAIL"));
3447 _cupsLangPrintf(stdout
,
3448 _(" **FAIL** Default option code cannot be "
3449 "interpreted: %s"), cupsRasterErrorString());
3455 * Try a test of custom page size code, if available...
3458 if (!ppdPageSize(ppd
, "Custom.612x792"))
3461 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3463 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3466 _cupsLangPuts(stdout
, _(" FAIL"));
3469 _cupsLangPrintf(stdout
,
3470 _(" **FAIL** Default option code cannot be "
3471 "interpreted: %s"), cupsRasterErrorString());
3481 * 'usage()' - Show program usage...
3487 _cupsLangPuts(stdout
, _("Usage: cupstestppd [options] filename1.ppd[.gz] "
3488 "[... filenameN.ppd[.gz]]"));
3489 _cupsLangPuts(stdout
, _(" program | cupstestppd [options] -"));
3490 _cupsLangPuts(stdout
, "");
3491 _cupsLangPuts(stdout
, _("Options:"));
3492 _cupsLangPuts(stdout
, "");
3493 _cupsLangPuts(stdout
, _(" -I {filename,filters,none,profiles}"));
3494 _cupsLangPuts(stdout
, _(" Ignore specific warnings."));
3495 _cupsLangPuts(stdout
, _(" -R root-directory Set alternate root."));
3496 _cupsLangPuts(stdout
, _(" -W {all,none,constraints,defaults,duplex,"
3497 "filters,profiles,sizes,translations}"));
3498 _cupsLangPuts(stdout
, _(" Issue warnings instead of "
3500 _cupsLangPuts(stdout
, _(" -q Run silently."));
3501 _cupsLangPuts(stdout
, _(" -r Use 'relaxed' open mode."));
3502 _cupsLangPuts(stdout
, _(" -v Be slightly verbose."));
3503 _cupsLangPuts(stdout
, _(" -vv Be very verbose."));
3510 * 'valid_path()' - Check whether a path has the correct capitalization.
3513 static int /* O - Errors found */
3514 valid_path(const char *keyword
, /* I - Keyword using path */
3515 const char *path
, /* I - Path to check */
3516 int errors
, /* I - Errors found */
3517 int verbose
, /* I - Verbosity level */
3518 int warn
) /* I - Warnings only? */
3520 cups_dir_t
*dir
; /* Current directory */
3521 cups_dentry_t
*dentry
; /* Current directory entry */
3522 char temp
[1024], /* Temporary path */
3523 *ptr
; /* Pointer into temporary path */
3524 const char *prefix
; /* WARN/FAIL prefix */
3527 prefix
= warn
? " WARN " : "**FAIL**";
3530 * Loop over the components of the path, checking that the entry exists with
3531 * the same capitalization...
3534 strlcpy(temp
, path
, sizeof(temp
));
3536 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3539 * Chop off the trailing component so temp == dirname and ptr == basename.
3545 * Try opening the directory containing the base name...
3549 dir
= cupsDirOpen(temp
);
3551 dir
= cupsDirOpen("/");
3557 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3559 if (!strcmp(dentry
->filename
, ptr
))
3567 * Display an error if the filename doesn't exist with the same
3573 if (!warn
&& !errors
&& !verbose
)
3574 _cupsLangPuts(stdout
, _(" FAIL"));
3577 _cupsLangPrintf(stdout
,
3578 _(" %s %s file \"%s\" has the wrong "
3579 "capitalization."), prefix
, keyword
, path
);
3593 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3596 static int /* O - 1 if valid, 0 if not */
3597 valid_utf8(const char *s
) /* I - String to check */
3604 * Check for valid UTF-8 sequence...
3607 if ((*s
& 0xc0) == 0x80)
3608 return (0); /* Illegal suffix byte */
3609 else if ((*s
& 0xe0) == 0xc0)
3612 * 2-byte sequence...
3617 if ((*s
& 0xc0) != 0x80)
3618 return (0); /* Missing suffix byte */
3620 else if ((*s
& 0xf0) == 0xe0)
3623 * 3-byte sequence...
3628 if ((*s
& 0xc0) != 0x80)
3629 return (0); /* Missing suffix byte */
3633 if ((*s
& 0xc0) != 0x80)
3634 return (0); /* Missing suffix byte */
3636 else if ((*s
& 0xf8) == 0xf0)
3639 * 4-byte sequence...
3644 if ((*s
& 0xc0) != 0x80)
3645 return (0); /* Missing suffix byte */
3649 if ((*s
& 0xc0) != 0x80)
3650 return (0); /* Missing suffix byte */
3654 if ((*s
& 0xc0) != 0x80)
3655 return (0); /* Missing suffix byte */
3658 return (0); /* Bad sequence */
3669 * End of "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $".