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.\n"));
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.\n"));
292 * Open the PPD file...
295 if (files
&& verbose
>= 0)
296 _cupsLangPuts(stdout
, "\n");
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\n"),
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 5.2.\n"));
355 case PPD_MISSING_VALUE
:
356 _cupsLangPuts(stdout
,
357 _(" REF: Page 20, section 3.4.\n"));
359 case PPD_BAD_OPEN_GROUP
:
360 case PPD_NESTED_OPEN_GROUP
:
361 _cupsLangPuts(stdout
,
362 _(" REF: Pages 45-46, section 5.2.\n"));
364 case PPD_BAD_OPEN_UI
:
365 case PPD_NESTED_OPEN_UI
:
366 _cupsLangPuts(stdout
,
367 _(" REF: Pages 42-45, section 5.2.\n"));
369 case PPD_BAD_ORDER_DEPENDENCY
:
370 _cupsLangPuts(stdout
,
371 _(" REF: Pages 48-49, section 5.2.\n"));
373 case PPD_BAD_UI_CONSTRAINTS
:
374 _cupsLangPuts(stdout
,
375 _(" REF: Pages 52-54, section 5.2.\n"));
377 case PPD_MISSING_ASTERISK
:
378 _cupsLangPuts(stdout
,
379 _(" REF: Page 15, section 3.2.\n"));
381 case PPD_LINE_TOO_LONG
:
382 _cupsLangPuts(stdout
,
383 _(" REF: Page 15, section 3.1.\n"));
385 case PPD_ILLEGAL_CHARACTER
:
386 _cupsLangPuts(stdout
,
387 _(" REF: Page 15, section 3.1.\n"));
389 case PPD_ILLEGAL_MAIN_KEYWORD
:
390 _cupsLangPuts(stdout
,
391 _(" REF: Pages 16-17, section 3.2.\n"));
393 case PPD_ILLEGAL_OPTION_KEYWORD
:
394 _cupsLangPuts(stdout
,
395 _(" REF: Page 19, section 3.3.\n"));
397 case PPD_ILLEGAL_TRANSLATION
:
398 _cupsLangPuts(stdout
,
399 _(" REF: Page 27, section 3.5.\n"));
405 check_basics(argv
[i
]);
413 * Show the header and then perform basic conformance tests (limited
414 * only by what the CUPS PPD functions actually load...)
421 _cupsLangPuts(stdout
,
422 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
424 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
426 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
428 for (j
= 0; j
< ppd
->num_filters
; j
++)
429 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
431 if (!test_raster(ppd
, verbose
))
437 * Look for default keywords with no matching option...
440 if (!(warn
& WARN_DEFAULTS
))
441 errors
= check_defaults(ppd
, errors
, verbose
, 0);
443 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
447 if (!errors
&& !verbose
)
448 _cupsLangPuts(stdout
, _(" FAIL\n"));
450 _cupsLangPuts(stdout
,
451 _(" **FAIL** REQUIRED DefaultImageableArea\n"
452 " REF: Page 102, section 5.15.\n"));
457 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
458 strcmp(attr
->value
, "Unknown"))
462 if (!errors
&& !verbose
)
463 _cupsLangPuts(stdout
, _(" FAIL\n"));
465 _cupsLangPrintf(stdout
,
466 _(" **FAIL** BAD DefaultImageableArea %s\n"
467 " REF: Page 102, section 5.15.\n"),
476 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
479 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
483 if (!errors
&& !verbose
)
484 _cupsLangPuts(stdout
, _(" FAIL\n"));
486 _cupsLangPuts(stdout
,
487 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
488 " REF: Page 103, section 5.15.\n"));
493 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
494 strcmp(attr
->value
, "Unknown"))
498 if (!errors
&& !verbose
)
499 _cupsLangPuts(stdout
, _(" FAIL\n"));
501 _cupsLangPrintf(stdout
,
502 _(" **FAIL** BAD DefaultPaperDimension %s\n"
503 " REF: Page 103, section 5.15.\n"),
509 else if (verbose
> 0)
510 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
512 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
513 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
516 * Verify that we have a default choice...
519 if (option
->defchoice
[0])
521 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
522 strcmp(option
->defchoice
, "Unknown"))
526 if (!errors
&& !verbose
)
527 _cupsLangPuts(stdout
, _(" FAIL\n"));
529 _cupsLangPrintf(stdout
,
530 _(" **FAIL** BAD Default%s %s\n"
531 " REF: Page 40, section 4.5.\n"),
532 option
->keyword
, option
->defchoice
);
537 else if (verbose
> 0)
538 _cupsLangPrintf(stdout
,
539 _(" PASS Default%s\n"),
546 if (!errors
&& !verbose
)
547 _cupsLangPuts(stdout
, _(" FAIL\n"));
549 _cupsLangPrintf(stdout
,
550 _(" **FAIL** REQUIRED Default%s\n"
551 " REF: Page 40, section 4.5.\n"),
559 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
561 for (ptr
= attr
->value
; *ptr
; ptr
++)
562 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
569 if (!errors
&& !verbose
)
570 _cupsLangPuts(stdout
, _(" FAIL\n"));
572 _cupsLangPrintf(stdout
,
573 _(" **FAIL** Bad FileVersion \"%s\"\n"
574 " REF: Page 56, section 5.3.\n"),
580 else if (verbose
> 0)
581 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
587 if (!errors
&& !verbose
)
588 _cupsLangPuts(stdout
, _(" FAIL\n"));
590 _cupsLangPuts(stdout
,
591 _(" **FAIL** REQUIRED FileVersion\n"
592 " REF: Page 56, section 5.3.\n"));
598 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
601 if (*ptr
== '4' && ptr
[1] == '.')
604 for (ptr
+= 2; *ptr
; ptr
++)
605 if (!isdigit(*ptr
& 255))
613 if (!errors
&& !verbose
)
614 _cupsLangPuts(stdout
, _(" FAIL\n"));
616 _cupsLangPrintf(stdout
,
617 _(" **FAIL** Bad FormatVersion \"%s\"\n"
618 " REF: Page 56, section 5.3.\n"),
624 else if (verbose
> 0)
625 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
631 if (!errors
&& !verbose
)
632 _cupsLangPuts(stdout
, _(" FAIL\n"));
634 _cupsLangPuts(stdout
,
635 _(" **FAIL** REQUIRED FormatVersion\n"
636 " REF: Page 56, section 5.3.\n"));
642 if (ppd
->lang_encoding
!= NULL
)
645 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
647 else if (ppdversion
> 40)
651 if (!errors
&& !verbose
)
652 _cupsLangPuts(stdout
, _(" FAIL\n"));
654 _cupsLangPuts(stdout
,
655 _(" **FAIL** REQUIRED LanguageEncoding\n"
656 " REF: Pages 56-57, section 5.3.\n"));
662 if (ppd
->lang_version
!= NULL
)
665 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
671 if (!errors
&& !verbose
)
672 _cupsLangPuts(stdout
, _(" FAIL\n"));
674 _cupsLangPuts(stdout
,
675 _(" **FAIL** REQUIRED LanguageVersion\n"
676 " REF: Pages 57-58, section 5.3.\n"));
682 if (ppd
->manufacturer
!= NULL
)
684 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
685 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
689 if (!errors
&& !verbose
)
690 _cupsLangPuts(stdout
, _(" FAIL\n"));
692 _cupsLangPuts(stdout
,
693 _(" **FAIL** BAD Manufacturer (should be "
695 " REF: Page 211, table D.1.\n"));
700 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
701 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
705 if (!errors
&& !verbose
)
706 _cupsLangPuts(stdout
, _(" FAIL\n"));
708 _cupsLangPuts(stdout
,
709 _(" **FAIL** BAD Manufacturer (should be "
711 " REF: Page 211, table D.1.\n"));
716 else if (verbose
> 0)
717 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
719 else if (ppdversion
>= 43)
723 if (!errors
&& !verbose
)
724 _cupsLangPuts(stdout
, _(" FAIL\n"));
726 _cupsLangPuts(stdout
,
727 _(" **FAIL** REQUIRED Manufacturer\n"
728 " REF: Pages 58-59, section 5.3.\n"));
734 if (ppd
->modelname
!= NULL
)
736 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
737 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
744 if (!errors
&& !verbose
)
745 _cupsLangPuts(stdout
, _(" FAIL\n"));
747 _cupsLangPrintf(stdout
,
748 _(" **FAIL** BAD ModelName - \"%c\" not "
749 "allowed in string.\n"
750 " REF: Pages 59-60, section 5.3.\n"),
756 else if (verbose
> 0)
757 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
763 if (!errors
&& !verbose
)
764 _cupsLangPuts(stdout
, _(" FAIL\n"));
766 _cupsLangPuts(stdout
,
767 _(" **FAIL** REQUIRED ModelName\n"
768 " REF: Pages 59-60, section 5.3.\n"));
774 if (ppd
->nickname
!= NULL
)
777 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
783 if (!errors
&& !verbose
)
784 _cupsLangPuts(stdout
, _(" FAIL\n"));
786 _cupsLangPuts(stdout
,
787 _(" **FAIL** REQUIRED NickName\n"
788 " REF: Page 60, section 5.3.\n"));
794 if (ppdFindOption(ppd
, "PageSize") != NULL
)
797 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
803 if (!errors
&& !verbose
)
804 _cupsLangPuts(stdout
, _(" FAIL\n"));
806 _cupsLangPuts(stdout
,
807 _(" **FAIL** REQUIRED PageSize\n"
808 " REF: Pages 99-100, section 5.14.\n"));
814 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
817 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
823 if (!errors
&& !verbose
)
824 _cupsLangPuts(stdout
, _(" FAIL\n"));
826 _cupsLangPuts(stdout
,
827 _(" **FAIL** REQUIRED PageRegion\n"
828 " REF: Page 100, section 5.14.\n"));
834 if (ppd
->pcfilename
!= NULL
)
837 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
839 else if (!(ignore
& WARN_FILENAME
))
843 if (!errors
&& !verbose
)
844 _cupsLangPuts(stdout
, _(" FAIL\n"));
846 _cupsLangPuts(stdout
,
847 _(" **FAIL** REQUIRED PCFileName\n"
848 " REF: Pages 61-62, section 5.3.\n"));
854 if (ppd
->product
!= NULL
)
856 if (ppd
->product
[0] != '(' ||
857 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
861 if (!errors
&& !verbose
)
862 _cupsLangPuts(stdout
, _(" FAIL\n"));
864 _cupsLangPuts(stdout
,
865 _(" **FAIL** BAD Product - not \"(string)\".\n"
866 " REF: Page 62, section 5.3.\n"));
871 else if (verbose
> 0)
872 _cupsLangPuts(stdout
, _(" PASS Product\n"));
878 if (!errors
&& !verbose
)
879 _cupsLangPuts(stdout
, _(" FAIL\n"));
881 _cupsLangPuts(stdout
,
882 _(" **FAIL** REQUIRED Product\n"
883 " REF: Page 62, section 5.3.\n"));
889 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
892 char junkstr
[255]; /* Temp string */
893 int junkint
; /* Temp integer */
896 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
900 if (!errors
&& !verbose
)
901 _cupsLangPuts(stdout
, _(" FAIL\n"));
903 _cupsLangPuts(stdout
,
904 _(" **FAIL** BAD PSVersion - not \"(string) "
906 " REF: Pages 62-64, section 5.3.\n"));
911 else if (verbose
> 0)
912 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
918 if (!errors
&& !verbose
)
919 _cupsLangPuts(stdout
, _(" FAIL\n"));
921 _cupsLangPuts(stdout
,
922 _(" **FAIL** REQUIRED PSVersion\n"
923 " REF: Pages 62-64, section 5.3.\n"));
929 if (ppd
->shortnickname
!= NULL
)
931 if (strlen(ppd
->shortnickname
) > 31)
935 if (!errors
&& !verbose
)
936 _cupsLangPuts(stdout
, _(" FAIL\n"));
938 _cupsLangPuts(stdout
,
939 _(" **FAIL** BAD ShortNickName - longer "
941 " REF: Pages 64-65, section 5.3.\n"));
946 else if (verbose
> 0)
947 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
949 else if (ppdversion
>= 43)
953 if (!errors
&& !verbose
)
954 _cupsLangPuts(stdout
, _(" FAIL\n"));
956 _cupsLangPuts(stdout
,
957 _(" **FAIL** REQUIRED ShortNickName\n"
958 " REF: Page 64-65, section 5.3.\n"));
964 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
965 strstr(ppd
->patches
, "*End"))
969 if (!errors
&& !verbose
)
970 _cupsLangPuts(stdout
, _(" FAIL\n"));
972 _cupsLangPuts(stdout
,
973 _(" **FAIL** BAD JobPatchFile attribute in file\n"
974 " REF: Page 24, section 3.4.\n"));
981 * Check for page sizes without the corresponding ImageableArea or
982 * PaperDimension values...
985 if (ppd
->num_sizes
== 0)
989 if (!errors
&& !verbose
)
990 _cupsLangPuts(stdout
, _(" FAIL\n"));
992 _cupsLangPuts(stdout
,
993 _(" **FAIL** REQUIRED PageSize\n"
994 " REF: Page 41, section 5.\n"
995 " REF: Page 99, section 5.14.\n"));
1002 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1005 * Don't check custom size...
1008 if (!strcmp(size
->name
, "Custom"))
1012 * Check for ImageableArea...
1015 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1016 size
->right
== 0.0 && size
->top
== 0.0)
1020 if (!errors
&& !verbose
)
1021 _cupsLangPuts(stdout
, _(" FAIL\n"));
1023 _cupsLangPrintf(stdout
,
1024 _(" **FAIL** REQUIRED ImageableArea for "
1026 " REF: Page 41, section 5.\n"
1027 " REF: Page 102, section 5.15.\n"),
1035 * Check for PaperDimension...
1038 if (size
->width
== 0.0 && size
->length
== 0.0)
1042 if (!errors
&& !verbose
)
1043 _cupsLangPuts(stdout
, _(" FAIL\n"));
1045 _cupsLangPrintf(stdout
,
1046 _(" **FAIL** REQUIRED PaperDimension "
1048 " REF: Page 41, section 5.\n"
1049 " REF: Page 103, section 5.15.\n"),
1059 * Check for valid Resolution, JCLResolution, or SetResolution values...
1062 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1063 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1064 option
= ppdFindOption(ppd
, "SetResolution");
1068 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
1071 * Verify that all resolution options are of the form NNNdpi
1075 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1076 if (ptr
> choice
->choice
&& xdpi
> 0)
1079 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1086 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1091 if (!errors
&& !verbose
)
1092 _cupsLangPuts(stdout
, _(" FAIL\n"));
1094 _cupsLangPrintf(stdout
,
1095 _(" **FAIL** Bad %s choice %s\n"
1096 " REF: Page 84, section 5.9\n"),
1097 option
->keyword
, choice
->choice
);
1105 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1106 strcmp(attr
->name
, "1284DeviceID"))
1110 if (!errors
&& !verbose
)
1111 _cupsLangPuts(stdout
, _(" FAIL\n"));
1113 _cupsLangPrintf(stdout
,
1114 _(" **FAIL** %s must be 1284DeviceID\n"
1115 " REF: Page 72, section 5.5\n"),
1122 errors
= check_case(ppd
, errors
, verbose
);
1124 if (!(warn
& WARN_CONSTRAINTS
))
1125 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1127 if (!(warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1128 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1130 if (!(warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1131 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1133 if (!(warn
& WARN_SIZES
))
1134 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1136 if (!(warn
& WARN_TRANSLATIONS
))
1137 errors
= check_translations(ppd
, errors
, verbose
, 0);
1139 if (!(warn
& WARN_DUPLEX
))
1140 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1142 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1146 * This file contains localizations, check for conformance of the
1147 * base translation...
1150 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1152 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1154 if (!errors
&& !verbose
)
1155 _cupsLangPuts(stdout
, _(" FAIL\n"));
1158 _cupsLangPrintf(stdout
,
1159 _(" **FAIL** Bad LanguageEncoding %s - "
1160 "must be ISOLatin1\n"),
1161 attr
->value
? attr
->value
: "(null)");
1166 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1168 if (!errors
&& !verbose
)
1169 _cupsLangPuts(stdout
, _(" FAIL\n"));
1172 _cupsLangPrintf(stdout
,
1173 _(" **FAIL** Bad LanguageVersion %s - "
1174 "must be English\n"),
1175 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1181 * Loop through all options and choices...
1184 for (option
= ppdFirstOption(ppd
);
1186 option
= ppdNextOption(ppd
))
1189 * Check for special characters outside A0 to BF, F7, or F8
1190 * that are used for languages other than English.
1193 for (ptr
= option
->text
; *ptr
; ptr
++)
1194 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1195 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1200 if (!errors
&& !verbose
)
1201 _cupsLangPuts(stdout
, _(" FAIL\n"));
1204 _cupsLangPrintf(stdout
,
1205 _(" **FAIL** Default translation "
1206 "string for option %s contains 8-bit "
1213 for (j
= 0; j
< option
->num_choices
; j
++)
1216 * Check for special characters outside A0 to BF, F7, or F8
1217 * that are used for languages other than English.
1220 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1221 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1222 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1227 if (!errors
&& !verbose
)
1228 _cupsLangPuts(stdout
, _(" FAIL\n"));
1231 _cupsLangPrintf(stdout
,
1232 _(" **FAIL** Default translation "
1233 "string for option %s choice %s contains "
1234 "8-bit characters\n"),
1236 option
->choices
[j
].choice
);
1246 * Final pass/fail notification...
1250 status
= ERROR_CONFORMANCE
;
1252 _cupsLangPuts(stdout
, _(" PASS\n"));
1256 check_basics(argv
[i
]);
1258 if (warn
& WARN_DEFAULTS
)
1259 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1261 if (warn
& WARN_CONSTRAINTS
)
1262 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1264 if ((warn
& WARN_FILTERS
) && !(ignore
& WARN_FILTERS
))
1265 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1267 if ((warn
& WARN_PROFILES
) && !(ignore
& WARN_PROFILES
))
1268 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1270 if (warn
& WARN_SIZES
)
1271 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1273 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1275 if (warn
& WARN_TRANSLATIONS
)
1276 errors
= check_translations(ppd
, errors
, verbose
, 1);
1278 if (warn
& WARN_DUPLEX
)
1279 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1282 * Look for legacy duplex keywords...
1285 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1286 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1287 option
= ppdFindOption(ppd
, "KD03Duplex");
1290 _cupsLangPrintf(stdout
,
1291 _(" WARN Duplex option keyword %s may not "
1292 "work as expected and should be named Duplex\n"
1293 " REF: Page 122, section 5.17\n"),
1297 * Look for default keywords with no corresponding option...
1300 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1302 attr
= ppd
->attrs
[j
];
1304 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1305 !strcmp(attr
->name
, "DefaultColorSep") ||
1306 !strcmp(attr
->name
, "DefaultFont") ||
1307 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1308 !strcmp(attr
->name
, "DefaultImageableArea") ||
1309 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1310 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1311 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1312 !strcmp(attr
->name
, "DefaultResolution") ||
1313 !strcmp(attr
->name
, "DefaultScreenProc") ||
1314 !strcmp(attr
->name
, "DefaultTransfer"))
1317 if (!strncmp(attr
->name
, "Default", 7) &&
1318 !ppdFindOption(ppd
, attr
->name
+ 7))
1319 _cupsLangPrintf(stdout
,
1320 _(" WARN %s has no corresponding "
1325 ppdMarkDefaults(ppd
);
1326 if (ppdConflicts(ppd
))
1328 _cupsLangPuts(stdout
,
1329 _(" WARN Default choices conflicting\n"));
1331 show_conflicts(ppd
);
1334 if (ppdversion
< 43)
1336 _cupsLangPrintf(stdout
,
1337 _(" WARN Obsolete PPD version %.1f\n"
1338 " REF: Page 42, section 5.2.\n"),
1342 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1344 _cupsLangPuts(stdout
,
1345 _(" WARN LanguageEncoding required by PPD "
1347 " REF: Pages 56-57, section 5.3.\n"));
1350 if (!ppd
->manufacturer
&& ppdversion
< 43)
1352 _cupsLangPuts(stdout
,
1353 _(" WARN Manufacturer required by PPD "
1355 " REF: Pages 58-59, section 5.3.\n"));
1359 * Treat a PCFileName attribute longer than 12 characters as
1360 * a warning and not a hard error...
1363 if (!(ignore
& WARN_FILENAME
) && ppd
->pcfilename
)
1365 if (strlen(ppd
->pcfilename
) > 12)
1367 _cupsLangPuts(stdout
,
1368 _(" WARN PCFileName longer than 8.3 in "
1369 "violation of PPD spec.\n"
1370 " REF: Pages 61-62, section "
1374 if (!strcasecmp(ppd
->pcfilename
, "unused.ppd"))
1375 _cupsLangPuts(stdout
,
1376 _(" WARN PCFileName should contain a "
1377 "unique filename.\n"
1378 " REF: Pages 61-62, section "
1382 if (!ppd
->shortnickname
&& ppdversion
< 43)
1384 _cupsLangPuts(stdout
,
1385 _(" WARN ShortNickName required by PPD "
1387 " REF: Pages 64-65, section 5.3.\n"));
1391 * Check the Protocols line and flag PJL + BCP since TBCP is
1392 * usually used with PJL...
1397 if (strstr(ppd
->protocols
, "PJL") &&
1398 strstr(ppd
->protocols
, "BCP") &&
1399 !strstr(ppd
->protocols
, "TBCP"))
1401 _cupsLangPuts(stdout
,
1402 _(" WARN Protocols contains both PJL "
1403 "and BCP; expected TBCP.\n"
1404 " REF: Pages 78-79, section 5.7.\n"));
1407 if (strstr(ppd
->protocols
, "PJL") &&
1408 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1410 _cupsLangPuts(stdout
,
1411 _(" WARN Protocols contains PJL but JCL "
1412 "attributes are not set.\n"
1413 " REF: Pages 78-79, section 5.7.\n"));
1418 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1419 * which are errors according to the spec but won't cause problems
1420 * with CUPS specifically...
1423 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1424 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1426 len
= (int)strlen(option
->keyword
);
1428 for (m
= 0, group2
= ppd
->groups
;
1429 m
< ppd
->num_groups
;
1431 for (n
= 0, option2
= group2
->options
;
1432 n
< group2
->num_options
;
1434 if (option
!= option2
&&
1435 len
< (int)strlen(option2
->keyword
) &&
1436 !strncmp(option
->keyword
, option2
->keyword
, len
))
1438 _cupsLangPrintf(stdout
,
1439 _(" WARN %s shares a common "
1441 " REF: Page 15, section "
1443 option
->keyword
, option2
->keyword
);
1451 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1453 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1457 * Then list the options, if "-v" was provided...
1462 _cupsLangPrintf(stdout
,
1464 " language_level = %d\n"
1465 " color_device = %s\n"
1466 " variable_sizes = %s\n"
1467 " landscape = %d\n",
1468 ppd
->language_level
,
1469 ppd
->color_device
? "TRUE" : "FALSE",
1470 ppd
->variable_sizes
? "TRUE" : "FALSE",
1473 switch (ppd
->colorspace
)
1476 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1479 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1482 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1485 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1488 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1492 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1493 ppd
->num_emulations
);
1494 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1495 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1496 j
, ppd
->emulations
[j
].name
);
1498 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1499 ppd
->lang_encoding
);
1500 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1502 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1503 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1504 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1505 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1507 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1508 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1509 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1510 ppd
->shortnickname
);
1511 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1512 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1514 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1515 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1517 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1520 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1522 _cupsLangPrintf(stdout
,
1523 " options[%d] = %s (%s) %s %s %.0f "
1525 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1526 sections
[option
->section
], option
->order
,
1527 option
->num_choices
);
1529 if (!strcmp(option
->keyword
, "PageSize") ||
1530 !strcmp(option
->keyword
, "PageRegion"))
1532 for (m
= option
->num_choices
, choice
= option
->choices
;
1536 size
= ppdPageSize(ppd
, choice
->choice
);
1539 _cupsLangPrintf(stdout
,
1541 choice
->choice
, choice
->text
);
1543 _cupsLangPrintf(stdout
,
1544 " %s (%s) = %.2fx%.2fin "
1545 "(%.1f,%.1f,%.1f,%.1f)",
1546 choice
->choice
, choice
->text
,
1547 size
->width
/ 72.0, size
->length
/ 72.0,
1548 size
->left
/ 72.0, size
->bottom
/ 72.0,
1549 size
->right
/ 72.0, size
->top
/ 72.0);
1551 if (!strcmp(option
->defchoice
, choice
->choice
))
1552 _cupsLangPuts(stdout
, " *\n");
1554 _cupsLangPuts(stdout
, "\n");
1559 for (m
= option
->num_choices
, choice
= option
->choices
;
1563 _cupsLangPrintf(stdout
, " %s (%s)",
1564 choice
->choice
, choice
->text
);
1566 if (!strcmp(option
->defchoice
, choice
->choice
))
1567 _cupsLangPuts(stdout
, " *\n");
1569 _cupsLangPuts(stdout
, "\n");
1575 _cupsLangPrintf(stdout
, " num_consts = %d\n",
1577 for (j
= 0; j
< ppd
->num_consts
; j
++)
1578 _cupsLangPrintf(stdout
,
1579 " consts[%d] = *%s %s *%s %s\n",
1580 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1581 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1583 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1585 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1586 _cupsLangPrintf(stdout
,
1587 " profiles[%d] = %s/%s %.3f %.3f "
1588 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1589 j
, ppd
->profiles
[j
].resolution
,
1590 ppd
->profiles
[j
].media_type
,
1591 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1592 ppd
->profiles
[j
].matrix
[0][0],
1593 ppd
->profiles
[j
].matrix
[0][1],
1594 ppd
->profiles
[j
].matrix
[0][2],
1595 ppd
->profiles
[j
].matrix
[1][0],
1596 ppd
->profiles
[j
].matrix
[1][1],
1597 ppd
->profiles
[j
].matrix
[1][2],
1598 ppd
->profiles
[j
].matrix
[2][0],
1599 ppd
->profiles
[j
].matrix
[2][1],
1600 ppd
->profiles
[j
].matrix
[2][2]);
1602 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1603 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1604 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1607 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1608 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1609 _cupsLangPrintf(stdout
,
1610 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1611 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1612 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1613 ppd
->attrs
[j
]->text
,
1614 ppd
->attrs
[j
]->value
?
1615 ppd
->attrs
[j
]->value
: "(null)");
1629 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1633 check_basics(const char *filename
) /* I - PPD file to check */
1635 cups_file_t
*fp
; /* File pointer */
1636 int ch
; /* Current character */
1637 int col
, /* Current column */
1638 whitespace
; /* Only seen whitespace? */
1639 int eol
; /* Line endings */
1640 int linenum
; /* Line number */
1641 int mixed
; /* Mixed line endings? */
1644 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1653 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1655 if (ch
== '\r' || ch
== '\n')
1659 if (eol
== EOL_NONE
)
1661 else if (eol
!= EOL_LF
)
1664 else if (ch
== '\r')
1666 if (cupsFilePeekChar(fp
) == '\n')
1668 cupsFileGetChar(fp
);
1670 if (eol
== EOL_NONE
)
1672 else if (eol
!= EOL_CRLF
)
1675 else if (eol
== EOL_NONE
)
1677 else if (eol
!= EOL_CR
)
1681 if (col
> 0 && whitespace
)
1682 _cupsLangPrintf(stdout
,
1683 _(" WARN Line %d only contains whitespace\n"),
1692 if (ch
!= ' ' && ch
!= '\t')
1700 _cupsLangPuts(stdout
,
1701 _(" WARN File contains a mix of CR, LF, and "
1702 "CR LF line endings\n"));
1704 if (eol
== EOL_CRLF
)
1705 _cupsLangPuts(stdout
,
1706 _(" WARN Non-Windows PPD files should use lines "
1707 "ending with only LF, not CR LF\n"));
1714 * 'check_constraints()' - Check UIConstraints in the PPD file.
1717 static int /* O - Errors found */
1718 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1719 int errors
, /* I - Errors found */
1720 int verbose
, /* I - Verbosity level */
1721 int warn
) /* I - Warnings only? */
1723 int i
; /* Looping var */
1724 const char *prefix
; /* WARN/FAIL prefix */
1725 ppd_const_t
*c
; /* Current UIConstraints data */
1726 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1727 const char *vptr
; /* Pointer into constraint value */
1728 char option
[PPD_MAX_NAME
],
1729 /* Option name/MainKeyword */
1730 choice
[PPD_MAX_NAME
],
1731 /* Choice/OptionKeyword */
1732 *ptr
; /* Pointer into option or choice */
1733 int num_options
; /* Number of options */
1734 cups_option_t
*options
; /* Options */
1735 ppd_option_t
*o
; /* PPD option */
1738 prefix
= warn
? " WARN " : "**FAIL**";
1742 * See what kind of constraint data we have in the PPD...
1745 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1748 * Check new-style cupsUIConstraints data...
1752 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1754 if (!constattr
->value
)
1756 if (!warn
&& !errors
&& !verbose
)
1757 _cupsLangPuts(stdout
, _(" FAIL\n"));
1759 _cupsLangPrintf(stdout
,
1760 _(" %s Empty cupsUIConstraints %s\n"),
1761 prefix
, constattr
->spec
);
1769 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1771 i
++, vptr
= strchr(vptr
+ 1, '*'));
1775 if (!warn
&& !errors
&& !verbose
)
1776 _cupsLangPuts(stdout
, _(" FAIL\n"));
1778 _cupsLangPrintf(stdout
,
1779 _(" %s Bad cupsUIConstraints %s: \"%s\"\n"),
1780 prefix
, constattr
->spec
, constattr
->value
);
1788 cupsArraySave(ppd
->sorted_attrs
);
1790 if (constattr
->spec
[0] &&
1791 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1793 if (!warn
&& !errors
&& !verbose
)
1794 _cupsLangPuts(stdout
, _(" FAIL\n"));
1796 _cupsLangPrintf(stdout
,
1797 _(" %s Missing cupsUIResolver %s\n"),
1798 prefix
, constattr
->spec
);
1804 cupsArrayRestore(ppd
->sorted_attrs
);
1809 for (vptr
= strchr(constattr
->value
, '*');
1811 vptr
= strchr(vptr
, '*'))
1814 * Extract "*Option Choice" or just "*Option"...
1817 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1818 if (ptr
< (option
+ sizeof(option
) - 1))
1823 while (isspace(*vptr
& 255))
1830 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1831 if (ptr
< (choice
+ sizeof(choice
) - 1))
1837 if (!strncasecmp(option
, "Custom", 6) && !strcasecmp(choice
, "True"))
1839 _cups_strcpy(option
, option
+ 6);
1840 strcpy(choice
, "Custom");
1843 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1845 if (!warn
&& !errors
&& !verbose
)
1846 _cupsLangPuts(stdout
, _(" FAIL\n"));
1848 _cupsLangPrintf(stdout
,
1849 _(" %s Missing option %s in "
1850 "cupsUIConstraints %s: \"%s\"\n"),
1851 prefix
, option
, constattr
->spec
, constattr
->value
);
1859 if (choice
[0] && !ppdFindChoice(o
, choice
))
1861 if (!warn
&& !errors
&& !verbose
)
1862 _cupsLangPuts(stdout
, _(" FAIL\n"));
1864 _cupsLangPrintf(stdout
,
1865 _(" %s Missing choice *%s %s in "
1866 "cupsUIConstraints %s: \"%s\"\n"),
1867 prefix
, option
, choice
, constattr
->spec
,
1877 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1880 for (i
= 0; i
< o
->num_choices
; i
++)
1881 if (strcasecmp(o
->choices
[i
].choice
, "None") &&
1882 strcasecmp(o
->choices
[i
].choice
, "Off") &&
1883 strcasecmp(o
->choices
[i
].choice
, "False"))
1885 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
1886 num_options
, &options
);
1893 * Resolvers must list at least two options...
1896 if (num_options
< 2)
1898 if (!warn
&& !errors
&& !verbose
)
1899 _cupsLangPuts(stdout
, _(" FAIL\n"));
1901 _cupsLangPrintf(stdout
,
1902 _(" %s cupsUIResolver %s does not list at least "
1903 "two different options\n"),
1904 prefix
, constattr
->spec
);
1911 * Test the resolver...
1914 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
1916 if (!warn
&& !errors
&& !verbose
)
1917 _cupsLangPuts(stdout
, _(" FAIL\n"));
1919 _cupsLangPrintf(stdout
,
1920 _(" %s cupsUIResolver %s causes a loop\n"),
1921 prefix
, constattr
->spec
);
1927 cupsFreeOptions(num_options
, options
);
1933 * Check old-style [Non]UIConstraints data...
1936 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1938 if (!strncasecmp(c
->option1
, "Custom", 6) &&
1939 !strcasecmp(c
->choice1
, "True"))
1941 strcpy(option
, c
->option1
+ 6);
1942 strcpy(choice
, "Custom");
1946 strcpy(option
, c
->option1
);
1947 strcpy(choice
, c
->choice1
);
1950 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1952 if (!warn
&& !errors
&& !verbose
)
1953 _cupsLangPuts(stdout
, _(" FAIL\n"));
1955 _cupsLangPrintf(stdout
,
1956 _(" %s Missing option %s in "
1957 "UIConstraints \"*%s %s *%s %s\"\n"),
1959 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1964 else if (choice
[0] && !ppdFindChoice(o
, choice
))
1966 if (!warn
&& !errors
&& !verbose
)
1967 _cupsLangPuts(stdout
, _(" FAIL\n"));
1969 _cupsLangPrintf(stdout
,
1970 _(" %s Missing choice *%s %s in "
1971 "UIConstraints \"*%s %s *%s %s\"\n"),
1972 prefix
, c
->option1
, c
->choice1
,
1973 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1979 if (!strncasecmp(c
->option2
, "Custom", 6) &&
1980 !strcasecmp(c
->choice2
, "True"))
1982 strcpy(option
, c
->option2
+ 6);
1983 strcpy(choice
, "Custom");
1987 strcpy(option
, c
->option2
);
1988 strcpy(choice
, c
->choice2
);
1991 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1993 if (!warn
&& !errors
&& !verbose
)
1994 _cupsLangPuts(stdout
, _(" FAIL\n"));
1996 _cupsLangPrintf(stdout
,
1997 _(" %s Missing option %s in "
1998 "UIConstraints \"*%s %s *%s %s\"\n"),
2000 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2005 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2007 if (!warn
&& !errors
&& !verbose
)
2008 _cupsLangPuts(stdout
, _(" FAIL\n"));
2010 _cupsLangPrintf(stdout
,
2011 _(" %s Missing choice *%s %s in "
2012 "UIConstraints \"*%s %s *%s %s\"\n"),
2013 prefix
, c
->option2
, c
->choice2
,
2014 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2027 * 'check_case()' - Check that there are no duplicate groups, options,
2028 * or choices that differ only by case.
2031 static int /* O - Errors found */
2032 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2033 int errors
, /* I - Errors found */
2034 int verbose
) /* I - Verbosity level */
2036 int i
, j
; /* Looping vars */
2037 ppd_group_t
*groupa
, /* First group */
2038 *groupb
; /* Second group */
2039 ppd_option_t
*optiona
, /* First option */
2040 *optionb
; /* Second option */
2041 ppd_choice_t
*choicea
, /* First choice */
2042 *choiceb
; /* Second choice */
2046 * Check that the groups do not have any duplicate names...
2049 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2050 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2051 if (!strcasecmp(groupa
->name
, groupb
->name
))
2053 if (!errors
&& !verbose
)
2054 _cupsLangPuts(stdout
, _(" FAIL\n"));
2057 _cupsLangPrintf(stdout
,
2058 _(" **FAIL** Group names %s and %s differ only "
2060 groupa
->name
, groupb
->name
);
2066 * Check that the options do not have any duplicate names...
2069 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2071 cupsArraySave(ppd
->options
);
2072 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2073 if (!strcasecmp(optiona
->keyword
, optionb
->keyword
))
2075 if (!errors
&& !verbose
)
2076 _cupsLangPuts(stdout
, _(" FAIL\n"));
2079 _cupsLangPrintf(stdout
,
2080 _(" **FAIL** Option names %s and %s differ only "
2082 optiona
->keyword
, optionb
->keyword
);
2086 cupsArrayRestore(ppd
->options
);
2089 * Then the choices...
2092 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2095 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2096 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2098 if (!errors
&& !verbose
)
2099 _cupsLangPuts(stdout
, _(" FAIL\n"));
2102 _cupsLangPrintf(stdout
,
2103 _(" **FAIL** Multiple occurrences of %s "
2104 "choice name %s\n"),
2105 optiona
->keyword
, choicea
->choice
);
2113 else if (!strcasecmp(choicea
->choice
, choiceb
->choice
))
2115 if (!errors
&& !verbose
)
2116 _cupsLangPuts(stdout
, _(" FAIL\n"));
2119 _cupsLangPrintf(stdout
,
2120 _(" **FAIL** %s choice names %s and %s "
2121 "differ only by case\n"),
2122 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2129 * Return the number of errors found...
2137 * 'check_defaults()' - Check default option keywords in the PPD file.
2140 static int /* O - Errors found */
2141 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2142 int errors
, /* I - Errors found */
2143 int verbose
, /* I - Verbosity level */
2144 int warn
) /* I - Warnings only? */
2146 int j
, k
; /* Looping vars */
2147 ppd_attr_t
*attr
; /* PPD attribute */
2148 ppd_option_t
*option
; /* Standard UI option */
2149 const char *prefix
; /* WARN/FAIL prefix */
2152 prefix
= warn
? " WARN " : "**FAIL**";
2154 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2156 attr
= ppd
->attrs
[j
];
2158 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2159 !strcmp(attr
->name
, "DefaultFont") ||
2160 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2161 !strcmp(attr
->name
, "DefaultImageableArea") ||
2162 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2163 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2164 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2165 !strcmp(attr
->name
, "DefaultResolution") ||
2166 !strcmp(attr
->name
, "DefaultTransfer"))
2169 if (!strncmp(attr
->name
, "Default", 7))
2171 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2172 strcmp(attr
->value
, "Unknown"))
2175 * Check that the default option value matches a choice...
2178 for (k
= 0; k
< option
->num_choices
; k
++)
2179 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2182 if (k
>= option
->num_choices
)
2184 if (!warn
&& !errors
&& !verbose
)
2185 _cupsLangPuts(stdout
, _(" FAIL\n"));
2188 _cupsLangPrintf(stdout
,
2189 _(" %s %s %s does not exist\n"),
2190 prefix
, attr
->name
, attr
->value
);
2204 * 'check_duplex()' - Check duplex keywords in the PPD file.
2207 static int /* O - Errors found */
2208 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2209 int errors
, /* I - Error found */
2210 int verbose
, /* I - Verbosity level */
2211 int warn
) /* I - Warnings only? */
2213 int i
; /* Looping var */
2214 ppd_option_t
*option
; /* PPD option */
2215 ppd_choice_t
*choice
; /* Current choice */
2216 const char *prefix
; /* Message prefix */
2219 prefix
= warn
? " WARN " : "**FAIL**";
2222 * Check for a duplex option, and for standard values...
2225 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2227 if (!ppdFindChoice(option
, "None"))
2231 if (!warn
&& !errors
&& !verbose
)
2232 _cupsLangPuts(stdout
, _(" FAIL\n"));
2234 _cupsLangPrintf(stdout
,
2235 _(" %s REQUIRED %s does not define "
2237 " REF: Page 122, section 5.17\n"),
2238 prefix
, option
->keyword
);
2245 for (i
= option
->num_choices
, choice
= option
->choices
;
2248 if (strcmp(choice
->choice
, "None") &&
2249 strcmp(choice
->choice
, "DuplexNoTumble") &&
2250 strcmp(choice
->choice
, "DuplexTumble") &&
2251 strcmp(choice
->choice
, "SimplexTumble"))
2255 if (!warn
&& !errors
&& !verbose
)
2256 _cupsLangPuts(stdout
, _(" FAIL\n"));
2258 _cupsLangPrintf(stdout
,
2259 _(" %s Bad %s choice %s\n"
2260 " REF: Page 122, section 5.17\n"),
2261 prefix
, option
->keyword
, choice
->choice
);
2274 * 'check_filters()' - Check filters in the PPD file.
2277 static int /* O - Errors found */
2278 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2279 const char *root
, /* I - Root directory */
2280 int errors
, /* I - Errors found */
2281 int verbose
, /* I - Verbosity level */
2282 int warn
) /* I - Warnings only? */
2284 int i
; /* Looping var */
2285 ppd_attr_t
*attr
; /* PPD attribute */
2286 const char *ptr
; /* Pointer into string */
2287 char super
[16], /* Super-type for filter */
2288 type
[256], /* Type for filter */
2289 program
[1024], /* Program/filter name */
2290 pathprog
[1024]; /* Complete path to program/filter */
2291 int cost
; /* Cost of filter */
2292 const char *prefix
; /* WARN/FAIL prefix */
2293 struct stat fileinfo
; /* File information */
2296 prefix
= warn
? " WARN " : "**FAIL**";
2302 for (i
= 0; i
< ppd
->num_filters
; i
++)
2304 if (sscanf(ppd
->filters
[i
], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2305 &cost
, program
) != 4)
2307 if (!warn
&& !errors
&& !verbose
)
2308 _cupsLangPuts(stdout
, _(" FAIL\n"));
2311 _cupsLangPrintf(stdout
,
2312 _(" %s Bad cupsFilter value \"%s\"\n"),
2313 prefix
, ppd
->filters
[i
]);
2318 else if (strcmp(program
, "-"))
2320 if (program
[0] == '/')
2321 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2324 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2325 ptr
= CUPS_SERVERBIN
;
2327 if (*ptr
== '/' || !*root
)
2328 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2331 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2335 if (stat(pathprog
, &fileinfo
))
2337 if (!warn
&& !errors
&& !verbose
)
2338 _cupsLangPuts(stdout
, _(" FAIL\n"));
2341 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
2342 "file \"%s\"\n"), prefix
, pathprog
);
2347 else if (fileinfo
.st_uid
!= 0 ||
2348 (fileinfo
.st_mode
& MODE_WRITE
) ||
2349 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2351 if (!warn
&& !errors
&& !verbose
)
2352 _cupsLangPuts(stdout
, _(" FAIL\n"));
2355 _cupsLangPrintf(stdout
, _(" %s Bad permissions on cupsFilter "
2356 "file \"%s\"\n"), prefix
, pathprog
);
2362 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2370 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2372 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2374 if (strcmp(attr
->name
, "cupsPreFilter"))
2376 if (!warn
&& !errors
&& !verbose
)
2377 _cupsLangPuts(stdout
, _(" FAIL\n"));
2380 _cupsLangPrintf(stdout
,
2381 _(" %s Bad spelling of %s - should be %s\n"),
2382 prefix
, attr
->name
, "cupsPreFilter");
2389 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2390 &cost
, program
) != 4)
2392 if (!warn
&& !errors
&& !verbose
)
2393 _cupsLangPuts(stdout
, _(" FAIL\n"));
2396 _cupsLangPrintf(stdout
,
2397 _(" %s Bad cupsPreFilter value \"%s\"\n"),
2398 prefix
, attr
->value
? attr
->value
: "");
2403 else if (strcmp(program
, "-"))
2405 if (program
[0] == '/')
2406 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2409 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2410 ptr
= CUPS_SERVERBIN
;
2412 if (*ptr
== '/' || !*root
)
2413 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2416 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2420 if (stat(pathprog
, &fileinfo
))
2422 if (!warn
&& !errors
&& !verbose
)
2423 _cupsLangPuts(stdout
, _(" FAIL\n"));
2426 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
2427 "file \"%s\"\n"), prefix
, pathprog
);
2432 else if (fileinfo
.st_uid
!= 0 ||
2433 (fileinfo
.st_mode
& MODE_WRITE
) ||
2434 (fileinfo
.st_mode
& MODE_MASK
) != MODE_PROGRAM
)
2436 if (!warn
&& !errors
&& !verbose
)
2437 _cupsLangPuts(stdout
, _(" FAIL\n"));
2440 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2441 "cupsPreFilter file \"%s\"\n"), prefix
,
2448 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2457 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2459 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2461 if (strcmp(attr
->name
, "APDialogExtension"))
2463 if (!warn
&& !errors
&& !verbose
)
2464 _cupsLangPuts(stdout
, _(" FAIL\n"));
2467 _cupsLangPrintf(stdout
,
2468 _(" %s Bad spelling of %s - should be %s\n"),
2469 prefix
, attr
->name
, "APDialogExtension");
2475 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2476 attr
->value
? attr
->value
: "(null)");
2478 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2480 if (!warn
&& !errors
&& !verbose
)
2481 _cupsLangPuts(stdout
, _(" FAIL\n"));
2484 _cupsLangPrintf(stdout
, _(" %s Missing "
2485 "APDialogExtension file \"%s\"\n"),
2491 else if (fileinfo
.st_uid
!= 0 ||
2492 (fileinfo
.st_mode
& MODE_WRITE
) ||
2493 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2495 if (!warn
&& !errors
&& !verbose
)
2496 _cupsLangPuts(stdout
, _(" FAIL\n"));
2499 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2500 "APDialogExtension file \"%s\"\n"), prefix
,
2507 errors
= valid_path("APDialogExtension", pathprog
, errors
, verbose
,
2515 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2517 if (strcmp(attr
->name
, "APPrinterIconPath"))
2519 if (!warn
&& !errors
&& !verbose
)
2520 _cupsLangPuts(stdout
, _(" FAIL\n"));
2523 _cupsLangPrintf(stdout
,
2524 _(" %s Bad spelling of %s - should be %s\n"),
2525 prefix
, attr
->name
, "APPrinterIconPath");
2531 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2532 attr
->value
? attr
->value
: "(null)");
2534 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2536 if (!warn
&& !errors
&& !verbose
)
2537 _cupsLangPuts(stdout
, _(" FAIL\n"));
2540 _cupsLangPrintf(stdout
, _(" %s Missing "
2541 "APPrinterIconPath file \"%s\"\n"),
2547 else if (fileinfo
.st_uid
!= 0 ||
2548 (fileinfo
.st_mode
& MODE_WRITE
) ||
2549 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2551 if (!warn
&& !errors
&& !verbose
)
2552 _cupsLangPuts(stdout
, _(" FAIL\n"));
2555 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2556 "APPrinterIconPath file \"%s\"\n"), prefix
,
2563 errors
= valid_path("APPrinterIconPath", pathprog
, errors
, verbose
,
2568 * APPrinterLowInkTool
2571 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2573 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2575 if (!warn
&& !errors
&& !verbose
)
2576 _cupsLangPuts(stdout
, _(" FAIL\n"));
2579 _cupsLangPrintf(stdout
,
2580 _(" %s Bad spelling of %s - should be %s\n"),
2581 prefix
, attr
->name
, "APPrinterLowInkTool");
2587 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2588 attr
->value
? attr
->value
: "(null)");
2590 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2592 if (!warn
&& !errors
&& !verbose
)
2593 _cupsLangPuts(stdout
, _(" FAIL\n"));
2596 _cupsLangPrintf(stdout
, _(" %s Missing "
2597 "APPrinterLowInkTool file \"%s\"\n"),
2603 else if (fileinfo
.st_uid
!= 0 ||
2604 (fileinfo
.st_mode
& MODE_WRITE
) ||
2605 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2607 if (!warn
&& !errors
&& !verbose
)
2608 _cupsLangPuts(stdout
, _(" FAIL\n"));
2611 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2612 "APPrinterLowInkTool file \"%s\"\n"), prefix
,
2619 errors
= valid_path("APPrinterLowInkTool", pathprog
, errors
, verbose
,
2624 * APPrinterUtilityPath
2627 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2629 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2631 if (!warn
&& !errors
&& !verbose
)
2632 _cupsLangPuts(stdout
, _(" FAIL\n"));
2635 _cupsLangPrintf(stdout
,
2636 _(" %s Bad spelling of %s - should be %s\n"),
2637 prefix
, attr
->name
, "APPrinterUtilityPath");
2643 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
,
2644 attr
->value
? attr
->value
: "(null)");
2646 if (!attr
->value
|| stat(pathprog
, &fileinfo
))
2648 if (!warn
&& !errors
&& !verbose
)
2649 _cupsLangPuts(stdout
, _(" FAIL\n"));
2652 _cupsLangPrintf(stdout
, _(" %s Missing "
2653 "APPrinterUtilityPath file \"%s\"\n"),
2659 else if (fileinfo
.st_uid
!= 0 ||
2660 (fileinfo
.st_mode
& MODE_WRITE
) ||
2661 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2663 if (!warn
&& !errors
&& !verbose
)
2664 _cupsLangPuts(stdout
, _(" FAIL\n"));
2667 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2668 "APPrinterUtilityPath file \"%s\"\n"), prefix
,
2675 errors
= valid_path("APPrinterUtilityPath", pathprog
, errors
, verbose
,
2680 * APScanAppBundleID and APScanAppPath
2683 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2685 if (strcmp(attr
->name
, "APScanAppPath"))
2687 if (!warn
&& !errors
&& !verbose
)
2688 _cupsLangPuts(stdout
, _(" FAIL\n"));
2691 _cupsLangPrintf(stdout
,
2692 _(" %s Bad spelling of %s - should be %s\n"),
2693 prefix
, attr
->name
, "APScanAppPath");
2699 if (!attr
->value
|| stat(attr
->value
, &fileinfo
))
2701 if (!warn
&& !errors
&& !verbose
)
2702 _cupsLangPuts(stdout
, _(" FAIL\n"));
2705 _cupsLangPrintf(stdout
, _(" %s Missing "
2706 "APScanAppPath file \"%s\"\n"),
2707 prefix
, attr
->value
? attr
->value
: "<NULL>");
2712 else if (fileinfo
.st_uid
!= 0 ||
2713 (fileinfo
.st_mode
& MODE_WRITE
) ||
2714 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DIRECTORY
)
2716 if (!warn
&& !errors
&& !verbose
)
2717 _cupsLangPuts(stdout
, _(" FAIL\n"));
2720 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2721 "APScanAppPath file \"%s\"\n"), prefix
,
2728 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2731 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2733 if (!warn
&& !errors
&& !verbose
)
2734 _cupsLangPuts(stdout
, _(" FAIL\n"));
2737 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2738 "APScanAppPath and APScanAppBundleID\n"),
2745 #endif /* __APPLE__ */
2752 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2755 static int /* O - Errors found */
2756 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2757 const char *root
, /* I - Root directory */
2758 int errors
, /* I - Errors found */
2759 int verbose
, /* I - Verbosity level */
2760 int warn
) /* I - Warnings only? */
2762 int i
; /* Looping var */
2763 ppd_attr_t
*attr
; /* PPD attribute */
2764 const char *ptr
; /* Pointer into string */
2765 const char *prefix
; /* WARN/FAIL prefix */
2766 char filename
[1024]; /* Profile filename */
2767 struct stat fileinfo
; /* File information */
2768 int num_profiles
= 0; /* Number of profiles */
2769 unsigned hash
, /* Current hash value */
2770 hashes
[1000]; /* Hash values of profile names */
2771 const char *specs
[1000]; /* Specifiers for profiles */
2774 prefix
= warn
? " WARN " : "**FAIL**";
2776 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
2778 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
2781 * Check for valid selector...
2784 for (i
= 0, ptr
= strchr(attr
->spec
, '.'); ptr
; ptr
= strchr(ptr
+ 1, '.'))
2787 if (!attr
->value
|| i
< 2)
2789 if (!warn
&& !errors
&& !verbose
)
2790 _cupsLangPuts(stdout
, _(" FAIL\n"));
2793 _cupsLangPrintf(stdout
,
2794 _(" %s Bad cupsICCProfile %s\n"),
2795 prefix
, attr
->spec
);
2804 * Check for valid profile filename...
2807 if (attr
->value
[0] == '/')
2808 snprintf(filename
, sizeof(filename
), "%s%s", root
, attr
->value
);
2811 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
2814 if (*ptr
== '/' || !*root
)
2815 snprintf(filename
, sizeof(filename
), "%s%s/profiles/%s", root
, ptr
,
2818 snprintf(filename
, sizeof(filename
), "%s/%s/profiles/%s", root
, ptr
,
2822 if (stat(filename
, &fileinfo
))
2824 if (!warn
&& !errors
&& !verbose
)
2825 _cupsLangPuts(stdout
, _(" FAIL\n"));
2828 _cupsLangPrintf(stdout
, _(" %s Missing cupsICCProfile "
2829 "file \"%s\"\n"), prefix
, filename
);
2834 else if (fileinfo
.st_uid
!= 0 ||
2835 (fileinfo
.st_mode
& MODE_WRITE
) ||
2836 (fileinfo
.st_mode
& MODE_MASK
) != MODE_DATAFILE
)
2838 if (!warn
&& !errors
&& !verbose
)
2839 _cupsLangPuts(stdout
, _(" FAIL\n"));
2842 _cupsLangPrintf(stdout
, _(" %s Bad permissions on "
2843 "cupsICCProfile file \"%s\"\n"), prefix
,
2850 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
2853 * Check for hash collisions...
2856 hash
= _ppdHashName(attr
->spec
);
2858 if (num_profiles
> 0)
2860 for (i
= 0; i
< num_profiles
; i
++)
2861 if (hashes
[i
] == hash
)
2864 if (i
< num_profiles
)
2866 if (!warn
&& !errors
&& !verbose
)
2867 _cupsLangPuts(stdout
, _(" FAIL\n"));
2870 _cupsLangPrintf(stdout
,
2871 _(" %s cupsICCProfile %s hash value "
2872 "collides with %s\n"), prefix
, attr
->spec
,
2881 * Remember up to 1000 profiles...
2884 if (num_profiles
< 1000)
2886 hashes
[num_profiles
] = hash
;
2887 specs
[num_profiles
] = attr
->spec
;
2897 * 'check_sizes()' - Check media sizes in the PPD file.
2900 static int /* O - Errors found */
2901 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
2902 int errors
, /* I - Errors found */
2903 int verbose
, /* I - Verbosity level */
2904 int warn
) /* I - Warnings only? */
2906 int i
; /* Looping vars */
2907 ppd_size_t
*size
; /* Current size */
2908 int width
, /* Custom width */
2909 length
; /* Custom length */
2910 const char *prefix
; /* WARN/FAIL prefix */
2911 ppd_option_t
*page_size
, /* PageSize option */
2912 *page_region
; /* PageRegion option */
2915 prefix
= warn
? " WARN " : "**FAIL**";
2917 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
2919 if (!warn
&& !errors
&& !verbose
)
2920 _cupsLangPuts(stdout
, _(" FAIL\n"));
2923 _cupsLangPrintf(stdout
,
2924 _(" %s Missing REQUIRED PageSize option\n"
2925 " REF: Page 99, section 5.14.\n"),
2932 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
2934 if (!warn
&& !errors
&& !verbose
)
2935 _cupsLangPuts(stdout
, _(" FAIL\n"));
2938 _cupsLangPrintf(stdout
,
2939 _(" %s Missing REQUIRED PageRegion option\n"
2940 " REF: Page 100, section 5.14.\n"),
2947 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
2950 * Check that the size name is standard...
2953 if (!strcmp(size
->name
, "Custom"))
2956 * Skip custom page size...
2961 else if (warn
!= 2 && size
->name
[0] == 'w' &&
2962 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
2965 * Validate device-specific size wNNNhNNN should have proper width and
2969 if (fabs(width
- size
->width
) >= 1.0 ||
2970 fabs(length
- size
->length
) >= 1.0)
2972 if (!warn
&& !errors
&& !verbose
)
2973 _cupsLangPuts(stdout
, _(" FAIL\n"));
2976 _cupsLangPrintf(stdout
,
2977 _(" %s Size \"%s\" has unexpected dimensions "
2979 prefix
, size
->name
, size
->width
, size
->length
);
2987 * Verify that the size is defined for both PageSize and PageRegion...
2990 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
2992 if (!warn
&& !errors
&& !verbose
)
2993 _cupsLangPuts(stdout
, _(" FAIL\n"));
2996 _cupsLangPrintf(stdout
,
2997 _(" %s Size \"%s\" defined for %s but not for "
2999 prefix
, size
->name
, "PageRegion", "PageSize");
3004 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3006 if (!warn
&& !errors
&& !verbose
)
3007 _cupsLangPuts(stdout
, _(" FAIL\n"));
3010 _cupsLangPrintf(stdout
,
3011 _(" %s Size \"%s\" defined for %s but not for "
3013 prefix
, size
->name
, "PageSize", "PageRegion");
3025 * 'check_translations()' - Check translations in the PPD file.
3028 static int /* O - Errors found */
3029 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3030 int errors
, /* I - Errors found */
3031 int verbose
, /* I - Verbosity level */
3032 int warn
) /* I - Warnings only? */
3034 int j
; /* Looping var */
3035 ppd_attr_t
*attr
; /* PPD attribute */
3036 cups_array_t
*languages
; /* Array of languages */
3037 int langlen
; /* Length of language */
3038 char *language
, /* Current language */
3039 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3040 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3041 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3042 cllkeyword
[PPD_MAX_NAME
];
3043 /* Custom option keyword (base) */
3044 ppd_option_t
*option
; /* Standard UI option */
3045 ppd_coption_t
*coption
; /* Custom option */
3046 ppd_cparam_t
*cparam
; /* Custom parameter */
3047 char ll
[3]; /* Base language */
3048 const char *prefix
; /* WARN/FAIL prefix */
3049 const char *text
; /* Pointer into UI text */
3052 prefix
= warn
? " WARN " : "**FAIL**";
3054 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3057 * This file contains localizations, check them...
3060 for (language
= (char *)cupsArrayFirst(languages
);
3062 language
= (char *)cupsArrayNext(languages
))
3064 langlen
= (int)strlen(language
);
3065 if (langlen
!= 2 && langlen
!= 5)
3067 if (!warn
&& !errors
&& !verbose
)
3068 _cupsLangPuts(stdout
, _(" FAIL\n"));
3071 _cupsLangPrintf(stdout
,
3072 _(" %s Bad language \"%s\"\n"),
3081 if (!strcmp(language
, "en"))
3084 strlcpy(ll
, language
, sizeof(ll
));
3087 * Loop through all options and choices...
3090 for (option
= ppdFirstOption(ppd
);
3092 option
= ppdNextOption(ppd
))
3094 if (!strcmp(option
->keyword
, "PageRegion"))
3097 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3098 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3100 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3101 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3103 if (!warn
&& !errors
&& !verbose
)
3104 _cupsLangPuts(stdout
, _(" FAIL\n"));
3107 _cupsLangPrintf(stdout
,
3108 _(" %s Missing \"%s\" translation "
3109 "string for option %s\n"),
3110 prefix
, language
, option
->keyword
);
3115 else if (!valid_utf8(attr
->text
))
3117 if (!warn
&& !errors
&& !verbose
)
3118 _cupsLangPuts(stdout
, _(" FAIL\n"));
3121 _cupsLangPrintf(stdout
,
3122 _(" %s Bad UTF-8 \"%s\" translation "
3123 "string for option %s\n"),
3124 prefix
, language
, option
->keyword
);
3130 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3132 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3135 for (j
= 0; j
< option
->num_choices
; j
++)
3138 * First see if this choice is a number; if so, don't require
3142 for (text
= option
->choices
[j
].text
; *text
; text
++)
3143 if (!strchr("0123456789-+.", *text
))
3150 * Check custom choices differently...
3153 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3154 (coption
= ppdFindCustomOption(ppd
,
3155 option
->keyword
)) != NULL
)
3157 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3158 language
, option
->keyword
);
3160 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3161 !valid_utf8(attr
->text
))
3163 if (!warn
&& !errors
&& !verbose
)
3164 _cupsLangPuts(stdout
, _(" FAIL\n"));
3167 _cupsLangPrintf(stdout
,
3168 _(" %s Bad UTF-8 \"%s\" "
3169 "translation string for option %s, "
3172 ckeyword
+ 1 + strlen(language
),
3179 if (strcasecmp(option
->keyword
, "PageSize"))
3181 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3183 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3185 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3186 language
, option
->keyword
);
3187 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3188 ll
, option
->keyword
);
3190 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3191 cparam
->name
)) == NULL
&&
3192 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3193 cparam
->name
)) == NULL
)
3195 if (!warn
&& !errors
&& !verbose
)
3196 _cupsLangPuts(stdout
, _(" FAIL\n"));
3199 _cupsLangPrintf(stdout
,
3200 _(" %s Missing \"%s\" "
3201 "translation string for option %s, "
3204 ckeyword
+ 1 + strlen(language
),
3210 else if (!valid_utf8(attr
->text
))
3212 if (!warn
&& !errors
&& !verbose
)
3213 _cupsLangPuts(stdout
, _(" FAIL\n"));
3216 _cupsLangPrintf(stdout
,
3217 _(" %s Bad UTF-8 \"%s\" "
3218 "translation string for option %s, "
3221 ckeyword
+ 1 + strlen(language
),
3230 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3231 option
->choices
[j
].choice
)) == NULL
&&
3232 (attr
= ppdFindAttr(ppd
, llkeyword
,
3233 option
->choices
[j
].choice
)) == NULL
)
3235 if (!warn
&& !errors
&& !verbose
)
3236 _cupsLangPuts(stdout
, _(" FAIL\n"));
3239 _cupsLangPrintf(stdout
,
3240 _(" %s Missing \"%s\" "
3241 "translation string for option %s, "
3243 prefix
, language
, option
->keyword
,
3244 option
->choices
[j
].choice
);
3249 else if (!valid_utf8(attr
->text
))
3251 if (!warn
&& !errors
&& !verbose
)
3252 _cupsLangPuts(stdout
, _(" FAIL\n"));
3255 _cupsLangPrintf(stdout
,
3256 _(" %s Bad UTF-8 \"%s\" "
3257 "translation string for option %s, "
3259 prefix
, language
, option
->keyword
,
3260 option
->choices
[j
].choice
);
3270 * Verify that we have the base language for each localized one...
3273 for (language
= (char *)cupsArrayFirst(languages
);
3275 language
= (char *)cupsArrayNext(languages
))
3279 * Lookup the base language...
3282 cupsArraySave(languages
);
3284 strlcpy(ll
, language
, sizeof(ll
));
3286 if (!cupsArrayFind(languages
, ll
) &&
3287 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3289 if (!warn
&& !errors
&& !verbose
)
3290 _cupsLangPuts(stdout
, _(" FAIL\n"));
3293 _cupsLangPrintf(stdout
,
3294 _(" %s No base translation \"%s\" "
3295 "is included in file\n"), prefix
, ll
);
3301 cupsArrayRestore(languages
);
3305 * Free memory used for the languages...
3308 _ppdFreeLanguages(languages
);
3316 * 'show_conflicts()' - Show option conflicts in a PPD file.
3320 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
3322 int i
, j
; /* Looping variables */
3323 ppd_const_t
*c
; /* Current constraint */
3324 ppd_option_t
*o1
, *o2
; /* Options */
3325 ppd_choice_t
*c1
, *c2
; /* Choices */
3329 * Loop through all of the UI constraints and report any options
3333 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3336 * Grab pointers to the first option...
3339 o1
= ppdFindOption(ppd
, c
->option1
);
3343 else if (c
->choice1
[0] != '\0')
3346 * This constraint maps to a specific choice.
3349 c1
= ppdFindChoice(o1
, c
->choice1
);
3354 * This constraint applies to any choice for this option.
3357 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3362 !strcasecmp(c1
->choice
, "None") ||
3363 !strcasecmp(c1
->choice
, "Off") ||
3364 !strcasecmp(c1
->choice
, "False"))
3369 * Grab pointers to the second option...
3372 o2
= ppdFindOption(ppd
, c
->option2
);
3376 else if (c
->choice2
[0] != '\0')
3379 * This constraint maps to a specific choice.
3382 c2
= ppdFindChoice(o2
, c
->choice2
);
3387 * This constraint applies to any choice for this option.
3390 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3395 !strcasecmp(c2
->choice
, "None") ||
3396 !strcasecmp(c2
->choice
, "Off") ||
3397 !strcasecmp(c2
->choice
, "False"))
3402 * If both options are marked then there is a conflict...
3405 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3406 _cupsLangPrintf(stdout
,
3407 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
3408 " (constraint=\"%s %s %s %s\")\n"),
3409 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3410 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3416 * 'test_raster()' - Test PostScript commands for raster printers.
3419 static int /* O - 1 on success, 0 on failure */
3420 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3421 int verbose
) /* I - Verbosity */
3423 cups_page_header2_t header
; /* Page header */
3426 ppdMarkDefaults(ppd
);
3427 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3430 _cupsLangPuts(stdout
, _(" FAIL\n"));
3433 _cupsLangPrintf(stdout
,
3434 _(" **FAIL** Default option code cannot be "
3435 "interpreted: %s\n"), cupsRasterErrorString());
3441 * Try a test of custom page size code, if available...
3444 if (!ppdPageSize(ppd
, "Custom.612x792"))
3447 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3449 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3452 _cupsLangPuts(stdout
, _(" FAIL\n"));
3455 _cupsLangPrintf(stdout
,
3456 _(" **FAIL** Default option code cannot be "
3457 "interpreted: %s\n"), cupsRasterErrorString());
3467 * 'usage()' - Show program usage...
3473 _cupsLangPuts(stdout
,
3474 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
3475 "[... filenameN.ppd[.gz]]\n"
3476 " program | cupstestppd [options] -\n"
3480 " -I {filename,filters,none,profiles}\n"
3481 " Ignore specific warnings\n"
3482 " -R root-directory Set alternate root\n"
3483 " -W {all,none,constraints,defaults,duplex,filters,"
3484 "profiles,sizes,translations}\n"
3485 " Issue warnings instead of errors\n"
3486 " -q Run silently\n"
3487 " -r Use 'relaxed' open mode\n"
3488 " -v Be slightly verbose\n"
3489 " -vv Be very verbose\n"));
3496 * 'valid_path()' - Check whether a path has the correct capitalization.
3499 static int /* O - Errors found */
3500 valid_path(const char *keyword
, /* I - Keyword using path */
3501 const char *path
, /* I - Path to check */
3502 int errors
, /* I - Errors found */
3503 int verbose
, /* I - Verbosity level */
3504 int warn
) /* I - Warnings only? */
3506 cups_dir_t
*dir
; /* Current directory */
3507 cups_dentry_t
*dentry
; /* Current directory entry */
3508 char temp
[1024], /* Temporary path */
3509 *ptr
; /* Pointer into temporary path */
3510 const char *prefix
; /* WARN/FAIL prefix */
3513 prefix
= warn
? " WARN " : "**FAIL**";
3516 * Loop over the components of the path, checking that the entry exists with
3517 * the same capitalization...
3520 strlcpy(temp
, path
, sizeof(temp
));
3522 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3525 * Chop off the trailing component so temp == dirname and ptr == basename.
3531 * Try opening the directory containing the base name...
3535 dir
= cupsDirOpen(temp
);
3537 dir
= cupsDirOpen("/");
3543 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3545 if (!strcmp(dentry
->filename
, ptr
))
3553 * Display an error if the filename doesn't exist with the same
3559 if (!warn
&& !errors
&& !verbose
)
3560 _cupsLangPuts(stdout
, _(" FAIL\n"));
3563 _cupsLangPrintf(stdout
,
3564 _(" %s %s file \"%s\" has the wrong "
3565 "capitalization\n"), prefix
, keyword
, path
);
3579 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3582 static int /* O - 1 if valid, 0 if not */
3583 valid_utf8(const char *s
) /* I - String to check */
3590 * Check for valid UTF-8 sequence...
3593 if ((*s
& 0xc0) == 0x80)
3594 return (0); /* Illegal suffix byte */
3595 else if ((*s
& 0xe0) == 0xc0)
3598 * 2-byte sequence...
3603 if ((*s
& 0xc0) != 0x80)
3604 return (0); /* Missing suffix byte */
3606 else if ((*s
& 0xf0) == 0xe0)
3609 * 3-byte sequence...
3614 if ((*s
& 0xc0) != 0x80)
3615 return (0); /* Missing suffix byte */
3619 if ((*s
& 0xc0) != 0x80)
3620 return (0); /* Missing suffix byte */
3622 else if ((*s
& 0xf8) == 0xf0)
3625 * 4-byte sequence...
3630 if ((*s
& 0xc0) != 0x80)
3631 return (0); /* Missing suffix byte */
3635 if ((*s
& 0xc0) != 0x80)
3636 return (0); /* Missing suffix byte */
3640 if ((*s
& 0xc0) != 0x80)
3641 return (0); /* Missing suffix byte */
3644 return (0); /* Bad sequence */
3655 * End of "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $".