4 * PPD test program for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 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 lines.
23 * check_constraints() - Check UIConstraints in the PPD file.
24 * check_defaults() - Check default option keywords in the PPD file.
25 * check_filters() - Check filters in the PPD file.
26 * check_translations() - Check translations in the PPD file.
27 * show_conflicts() - Show option conflicts in a PPD file.
28 * test_raster() - Test PostScript commands for raster printers.
29 * usage() - Show program usage...
30 * valid_utf8() - Check whether a string contains valid UTF-8 text.
34 * Include necessary headers...
37 #include <cups/string.h>
38 #include <cups/cups.h>
39 #include <cups/i18n.h>
40 #include <filter/raster.h>
47 * Error warning overrides...
56 WARN_TRANSLATIONS
= 8,
92 static void check_basics(const char *filename
);
93 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
95 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
97 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
98 int verbose
, int warn
);
99 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,\
101 static void show_conflicts(ppd_file_t
*ppd
);
102 static int test_raster(ppd_file_t
*ppd
, int verbose
);
103 static void usage(void);
104 static int valid_utf8(const char *s
);
108 * 'main()' - Main entry for test program.
111 int /* O - Exit status */
112 main(int argc
, /* I - Number of command-line args */
113 char *argv
[]) /* I - Command-line arguments */
115 int i
, j
, k
, m
, n
; /* Looping vars */
116 int len
; /* Length of option name */
117 char *opt
; /* Option character */
118 const char *ptr
; /* Pointer into string */
119 int files
; /* Number of files */
120 int verbose
; /* Want verbose output? */
121 int warn
; /* Which errors to just warn about */
122 int status
; /* Exit status */
123 int errors
; /* Number of conformance errors */
124 int ppdversion
; /* PPD spec version in PPD file */
125 ppd_status_t error
; /* Status of ppdOpen*() */
126 int line
; /* Line number for error */
127 struct stat statbuf
; /* File information */
128 char pathprog
[1024], /* Complete path to program/filter */
129 *root
; /* Root directory */
130 int xdpi
, /* X resolution */
131 ydpi
; /* Y resolution */
132 ppd_file_t
*ppd
; /* PPD file record */
133 ppd_attr_t
*attr
; /* PPD attribute */
134 ppd_size_t
*size
; /* Size record */
135 ppd_group_t
*group
; /* UI group */
136 ppd_option_t
*option
; /* Standard UI option */
137 ppd_group_t
*group2
; /* UI group */
138 ppd_option_t
*option2
; /* Standard UI option */
139 ppd_choice_t
*choice
; /* Standard UI option choice */
140 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
141 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
142 "JCL", "PAGE", "PROLOG" };
145 _cupsSetLocale(argv
);
148 * Display PPD files for each file listed on the command-line...
151 ppdSetConformance(PPD_CONFORM_STRICT
);
160 for (i
= 1; i
< argc
; i
++)
161 if (argv
[i
][0] == '-' && argv
[i
][1])
163 for (opt
= argv
[i
] + 1; *opt
; opt
++)
166 case 'R' : /* Alternate root directory */
175 case 'W' : /* Turn errors into warnings */
181 if (!strcmp(argv
[i
], "none"))
183 else if (!strcmp(argv
[i
], "constraints"))
184 warn
|= WARN_CONSTRAINTS
;
185 else if (!strcmp(argv
[i
], "defaults"))
186 warn
|= WARN_DEFAULTS
;
187 else if (!strcmp(argv
[i
], "filters"))
188 warn
|= WARN_FILTERS
;
189 else if (!strcmp(argv
[i
], "translations"))
190 warn
|= WARN_TRANSLATIONS
;
191 else if (!strcmp(argv
[i
], "all"))
197 case 'q' : /* Quiet mode */
200 _cupsLangPuts(stderr
,
201 _("cupstestppd: The -q option is incompatible "
202 "with the -v option.\n"));
209 case 'r' : /* Relaxed mode */
210 ppdSetConformance(PPD_CONFORM_RELAXED
);
213 case 'v' : /* Verbose mode */
216 _cupsLangPuts(stderr
,
217 _("cupstestppd: The -v option is incompatible "
218 "with the -q option.\n"));
233 * Open the PPD file...
236 if (files
&& verbose
>= 0)
237 _cupsLangPuts(stdout
, "\n");
241 if (argv
[i
][0] == '-')
250 ppd
= ppdOpen(stdin
);
255 * Read from a file...
259 printf("%s:", argv
[i
]);
261 ppd
= ppdOpenFile(argv
[i
]);
266 error
= ppdLastError(&line
);
268 if (error
<= PPD_ALLOC_ERROR
)
270 status
= ERROR_FILE_OPEN
;
273 _cupsLangPrintf(stdout
,
275 " **FAIL** Unable to open PPD file - %s\n"),
280 status
= ERROR_PPD_FORMAT
;
284 _cupsLangPrintf(stdout
,
286 " **FAIL** Unable to open PPD file - "
288 ppdErrorString(error
), line
);
292 case PPD_MISSING_PPDADOBE4
:
293 _cupsLangPuts(stdout
,
294 _(" REF: Page 42, section 5.2.\n"));
296 case PPD_MISSING_VALUE
:
297 _cupsLangPuts(stdout
,
298 _(" REF: Page 20, section 3.4.\n"));
300 case PPD_BAD_OPEN_GROUP
:
301 case PPD_NESTED_OPEN_GROUP
:
302 _cupsLangPuts(stdout
,
303 _(" REF: Pages 45-46, section 5.2.\n"));
305 case PPD_BAD_OPEN_UI
:
306 case PPD_NESTED_OPEN_UI
:
307 _cupsLangPuts(stdout
,
308 _(" REF: Pages 42-45, section 5.2.\n"));
310 case PPD_BAD_ORDER_DEPENDENCY
:
311 _cupsLangPuts(stdout
,
312 _(" REF: Pages 48-49, section 5.2.\n"));
314 case PPD_BAD_UI_CONSTRAINTS
:
315 _cupsLangPuts(stdout
,
316 _(" REF: Pages 52-54, section 5.2.\n"));
318 case PPD_MISSING_ASTERISK
:
319 _cupsLangPuts(stdout
,
320 _(" REF: Page 15, section 3.2.\n"));
322 case PPD_LINE_TOO_LONG
:
323 _cupsLangPuts(stdout
,
324 _(" REF: Page 15, section 3.1.\n"));
326 case PPD_ILLEGAL_CHARACTER
:
327 _cupsLangPuts(stdout
,
328 _(" REF: Page 15, section 3.1.\n"));
330 case PPD_ILLEGAL_MAIN_KEYWORD
:
331 _cupsLangPuts(stdout
,
332 _(" REF: Pages 16-17, section 3.2.\n"));
334 case PPD_ILLEGAL_OPTION_KEYWORD
:
335 _cupsLangPuts(stdout
,
336 _(" REF: Page 19, section 3.3.\n"));
338 case PPD_ILLEGAL_TRANSLATION
:
339 _cupsLangPuts(stdout
,
340 _(" REF: Page 27, section 3.5.\n"));
346 check_basics(argv
[i
]);
354 * Show the header and then perform basic conformance tests (limited
355 * only by what the CUPS PPD functions actually load...)
362 _cupsLangPuts(stdout
,
363 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
365 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
367 ppdversion
= (int)(10 * atof(attr
->value
) + 0.5);
369 for (j
= 0; j
< ppd
->num_filters
; j
++)
370 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
372 if (!test_raster(ppd
, verbose
))
378 * Look for default keywords with no matching option...
381 if (!(warn
& WARN_DEFAULTS
))
382 errors
= check_defaults(ppd
, errors
, verbose
, 0);
384 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
388 if (!errors
&& !verbose
)
389 _cupsLangPuts(stdout
, _(" FAIL\n"));
391 _cupsLangPuts(stdout
,
392 _(" **FAIL** REQUIRED DefaultImageableArea\n"
393 " REF: Page 102, section 5.15.\n"));
398 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
399 strcmp(attr
->value
, "Unknown"))
403 if (!errors
&& !verbose
)
404 _cupsLangPuts(stdout
, _(" FAIL\n"));
406 _cupsLangPrintf(stdout
,
407 _(" **FAIL** BAD DefaultImageableArea %s!\n"
408 " REF: Page 102, section 5.15.\n"),
417 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
420 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
424 if (!errors
&& !verbose
)
425 _cupsLangPuts(stdout
, _(" FAIL\n"));
427 _cupsLangPuts(stdout
,
428 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
429 " REF: Page 103, section 5.15.\n"));
434 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
435 strcmp(attr
->value
, "Unknown"))
439 if (!errors
&& !verbose
)
440 _cupsLangPuts(stdout
, _(" FAIL\n"));
442 _cupsLangPrintf(stdout
,
443 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
444 " REF: Page 103, section 5.15.\n"),
450 else if (verbose
> 0)
451 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
453 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
454 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
457 * Verify that we have a default choice...
460 if (option
->defchoice
[0])
462 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
463 strcmp(option
->defchoice
, "Unknown"))
467 if (!errors
&& !verbose
)
468 _cupsLangPuts(stdout
, _(" FAIL\n"));
470 _cupsLangPrintf(stdout
,
471 _(" **FAIL** BAD Default%s %s\n"
472 " REF: Page 40, section 4.5.\n"),
473 option
->keyword
, option
->defchoice
);
478 else if (verbose
> 0)
479 _cupsLangPrintf(stdout
,
480 _(" PASS Default%s\n"),
487 if (!errors
&& !verbose
)
488 _cupsLangPuts(stdout
, _(" FAIL\n"));
490 _cupsLangPrintf(stdout
,
491 _(" **FAIL** REQUIRED Default%s\n"
492 " REF: Page 40, section 4.5.\n"),
500 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
503 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
509 if (!errors
&& !verbose
)
510 _cupsLangPuts(stdout
, _(" FAIL\n"));
512 _cupsLangPuts(stdout
,
513 _(" **FAIL** REQUIRED FileVersion\n"
514 " REF: Page 56, section 5.3.\n"));
520 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
523 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
529 if (!errors
&& !verbose
)
530 _cupsLangPuts(stdout
, _(" FAIL\n"));
532 _cupsLangPuts(stdout
,
533 _(" **FAIL** REQUIRED FormatVersion\n"
534 " REF: Page 56, section 5.3.\n"));
540 if (ppd
->lang_encoding
!= NULL
)
543 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
545 else if (ppdversion
> 40)
549 if (!errors
&& !verbose
)
550 _cupsLangPuts(stdout
, _(" FAIL\n"));
552 _cupsLangPuts(stdout
,
553 _(" **FAIL** REQUIRED LanguageEncoding\n"
554 " REF: Pages 56-57, section 5.3.\n"));
560 if (ppd
->lang_version
!= NULL
)
563 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
569 if (!errors
&& !verbose
)
570 _cupsLangPuts(stdout
, _(" FAIL\n"));
572 _cupsLangPuts(stdout
,
573 _(" **FAIL** REQUIRED LanguageVersion\n"
574 " REF: Pages 57-58, section 5.3.\n"));
580 if (ppd
->manufacturer
!= NULL
)
582 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
583 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
587 if (!errors
&& !verbose
)
588 _cupsLangPuts(stdout
, _(" FAIL\n"));
590 _cupsLangPuts(stdout
,
591 _(" **FAIL** BAD Manufacturer (should be "
593 " REF: Page 211, table D.1.\n"));
598 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
599 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
603 if (!errors
&& !verbose
)
604 _cupsLangPuts(stdout
, _(" FAIL\n"));
606 _cupsLangPuts(stdout
,
607 _(" **FAIL** BAD Manufacturer (should be "
609 " REF: Page 211, table D.1.\n"));
614 else if (verbose
> 0)
615 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
617 else if (ppdversion
>= 43)
621 if (!errors
&& !verbose
)
622 _cupsLangPuts(stdout
, _(" FAIL\n"));
624 _cupsLangPuts(stdout
,
625 _(" **FAIL** REQUIRED Manufacturer\n"
626 " REF: Pages 58-59, section 5.3.\n"));
632 if (ppd
->modelname
!= NULL
)
634 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
635 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
642 if (!errors
&& !verbose
)
643 _cupsLangPuts(stdout
, _(" FAIL\n"));
645 _cupsLangPrintf(stdout
,
646 _(" **FAIL** BAD ModelName - \"%c\" not "
647 "allowed in string.\n"
648 " REF: Pages 59-60, section 5.3.\n"),
654 else if (verbose
> 0)
655 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
661 if (!errors
&& !verbose
)
662 _cupsLangPuts(stdout
, _(" FAIL\n"));
664 _cupsLangPuts(stdout
,
665 _(" **FAIL** REQUIRED ModelName\n"
666 " REF: Pages 59-60, section 5.3.\n"));
672 if (ppd
->nickname
!= NULL
)
675 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
681 if (!errors
&& !verbose
)
682 _cupsLangPuts(stdout
, _(" FAIL\n"));
684 _cupsLangPuts(stdout
,
685 _(" **FAIL** REQUIRED NickName\n"
686 " REF: Page 60, section 5.3.\n"));
692 if (ppdFindOption(ppd
, "PageSize") != NULL
)
695 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
701 if (!errors
&& !verbose
)
702 _cupsLangPuts(stdout
, _(" FAIL\n"));
704 _cupsLangPuts(stdout
,
705 _(" **FAIL** REQUIRED PageSize\n"
706 " REF: Pages 99-100, section 5.14.\n"));
712 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
715 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
721 if (!errors
&& !verbose
)
722 _cupsLangPuts(stdout
, _(" FAIL\n"));
724 _cupsLangPuts(stdout
,
725 _(" **FAIL** REQUIRED PageRegion\n"
726 " REF: Page 100, section 5.14.\n"));
732 if (ppd
->pcfilename
!= NULL
)
735 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
741 if (!errors
&& !verbose
)
742 _cupsLangPuts(stdout
, _(" FAIL\n"));
744 _cupsLangPuts(stdout
,
745 _(" **FAIL** REQUIRED PCFileName\n"
746 " REF: Pages 61-62, section 5.3.\n"));
752 if (ppd
->product
!= NULL
)
754 if (ppd
->product
[0] != '(' ||
755 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
759 if (!errors
&& !verbose
)
760 _cupsLangPuts(stdout
, _(" FAIL\n"));
762 _cupsLangPuts(stdout
,
763 _(" **FAIL** BAD Product - not \"(string)\".\n"
764 " REF: Page 62, section 5.3.\n"));
769 else if (verbose
> 0)
770 _cupsLangPuts(stdout
, _(" PASS Product\n"));
776 if (!errors
&& !verbose
)
777 _cupsLangPuts(stdout
, _(" FAIL\n"));
779 _cupsLangPuts(stdout
,
780 _(" **FAIL** REQUIRED Product\n"
781 " REF: Page 62, section 5.3.\n"));
787 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
790 char junkstr
[255]; /* Temp string */
791 int junkint
; /* Temp integer */
794 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
798 if (!errors
&& !verbose
)
799 _cupsLangPuts(stdout
, _(" FAIL\n"));
801 _cupsLangPuts(stdout
,
802 _(" **FAIL** BAD PSVersion - not \"(string) "
804 " REF: Pages 62-64, section 5.3.\n"));
809 else if (verbose
> 0)
810 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
816 if (!errors
&& !verbose
)
817 _cupsLangPuts(stdout
, _(" FAIL\n"));
819 _cupsLangPuts(stdout
,
820 _(" **FAIL** REQUIRED PSVersion\n"
821 " REF: Pages 62-64, section 5.3.\n"));
827 if (ppd
->shortnickname
!= NULL
)
829 if (strlen(ppd
->shortnickname
) > 31)
833 if (!errors
&& !verbose
)
834 _cupsLangPuts(stdout
, _(" FAIL\n"));
836 _cupsLangPuts(stdout
,
837 _(" **FAIL** BAD ShortNickName - longer "
839 " REF: Pages 64-65, section 5.3.\n"));
844 else if (verbose
> 0)
845 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
847 else if (ppdversion
>= 43)
851 if (!errors
&& !verbose
)
852 _cupsLangPuts(stdout
, _(" FAIL\n"));
854 _cupsLangPuts(stdout
,
855 _(" **FAIL** REQUIRED ShortNickName\n"
856 " REF: Page 64-65, section 5.3.\n"));
862 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
863 strstr(ppd
->patches
, "*End"))
867 if (!errors
&& !verbose
)
868 _cupsLangPuts(stdout
, _(" FAIL\n"));
870 _cupsLangPuts(stdout
,
871 _(" **FAIL** BAD JobPatchFile attribute in file\n"
872 " REF: Page 24, section 3.4.\n"));
879 * Check for page sizes without the corresponding ImageableArea or
880 * PaperDimension values...
883 if (ppd
->num_sizes
== 0)
887 if (!errors
&& !verbose
)
888 _cupsLangPuts(stdout
, _(" FAIL\n"));
890 _cupsLangPuts(stdout
,
891 _(" **FAIL** REQUIRED PageSize\n"
892 " REF: Page 41, section 5.\n"
893 " REF: Page 99, section 5.14.\n"));
900 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
903 * Don't check custom size...
906 if (!strcmp(size
->name
, "Custom"))
910 * Check for ImageableArea...
913 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
914 size
->right
== 0.0 && size
->top
== 0.0)
918 if (!errors
&& !verbose
)
919 _cupsLangPuts(stdout
, _(" FAIL\n"));
921 _cupsLangPrintf(stdout
,
922 _(" **FAIL** REQUIRED ImageableArea for "
924 " REF: Page 41, section 5.\n"
925 " REF: Page 102, section 5.15.\n"),
933 * Check for PaperDimension...
936 if (size
->width
== 0.0 && size
->length
== 0.0)
940 if (!errors
&& !verbose
)
941 _cupsLangPuts(stdout
, _(" FAIL\n"));
943 _cupsLangPrintf(stdout
,
944 _(" **FAIL** REQUIRED PaperDimension "
946 " REF: Page 41, section 5.\n"
947 " REF: Page 103, section 5.15.\n"),
957 * Check for valid Resolution, JCLResolution, or SetResolution values...
960 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
961 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
962 option
= ppdFindOption(ppd
, "SetResolution");
966 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
969 * Verify that all resolution options are of the form NNNdpi
973 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
974 if (ptr
> choice
->choice
&& xdpi
> 0)
977 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
984 if (xdpi
<= 0 || ydpi
<= 0 || strcmp(ptr
, "dpi"))
988 if (!errors
&& !verbose
)
989 _cupsLangPuts(stdout
, _(" FAIL\n"));
991 _cupsLangPrintf(stdout
,
992 _(" **FAIL** Bad %s choice %s!\n"
993 " REF: Page 84, section 5.9\n"),
994 option
->keyword
, choice
->choice
);
1003 * Check for a duplex option, and for standard values...
1006 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
1007 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1008 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1009 option
= ppdFindOption(ppd
, "KD03Duplex");
1013 if (ppdFindChoice(option
, "None") == NULL
)
1017 if (!errors
&& !verbose
)
1018 _cupsLangPuts(stdout
, _(" FAIL\n"));
1020 _cupsLangPrintf(stdout
,
1021 _(" **FAIL** REQUIRED %s does not define "
1023 " REF: Page 122, section 5.17\n"),
1030 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
1031 if (strcmp(choice
->choice
, "None") &&
1032 strcmp(choice
->choice
, "DuplexNoTumble") &&
1033 strcmp(choice
->choice
, "DuplexTumble") &&
1034 strcmp(choice
->choice
, "SimplexTumble"))
1038 if (!errors
&& !verbose
)
1039 _cupsLangPuts(stdout
, _(" FAIL\n"));
1041 _cupsLangPrintf(stdout
,
1042 _(" **FAIL** Bad %s choice %s!\n"
1043 " REF: Page 122, section 5.17\n"),
1044 option
->keyword
, choice
->choice
);
1051 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1052 strcmp(attr
->name
, "1284DeviceID"))
1056 if (!errors
&& !verbose
)
1057 _cupsLangPuts(stdout
, _(" FAIL\n"));
1059 _cupsLangPrintf(stdout
,
1060 _(" **FAIL** %s must be 1284DeviceID!\n"
1061 " REF: Page 72, section 5.5\n"),
1068 if (!(warn
& WARN_CONSTRAINTS
))
1069 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1071 if (!(warn
& WARN_FILTERS
))
1072 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1074 if (!(warn
& WARN_TRANSLATIONS
))
1075 errors
= check_translations(ppd
, errors
, verbose
, 0);
1077 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1081 * This file contains localizations, check for conformance of the
1082 * base translation...
1085 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1087 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1089 if (!errors
&& !verbose
)
1090 _cupsLangPuts(stdout
, _(" FAIL\n"));
1093 _cupsLangPrintf(stdout
,
1094 _(" **FAIL** Bad LanguageEncoding %s - "
1095 "must be ISOLatin1!\n"),
1096 attr
->value
? attr
->value
: "(null)");
1101 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1103 if (!errors
&& !verbose
)
1104 _cupsLangPuts(stdout
, _(" FAIL\n"));
1107 _cupsLangPrintf(stdout
,
1108 _(" **FAIL** Bad LanguageVersion %s - "
1109 "must be English!\n"),
1110 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1116 * Loop through all options and choices...
1119 for (option
= ppdFirstOption(ppd
);
1121 option
= ppdNextOption(ppd
))
1124 * Check for special characters outside A0 to BF, F7, or F8
1125 * that are used for languages other than English.
1128 for (ptr
= option
->text
; *ptr
; ptr
++)
1129 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1130 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1135 if (!errors
&& !verbose
)
1136 _cupsLangPuts(stdout
, _(" FAIL\n"));
1139 _cupsLangPrintf(stdout
,
1140 _(" **FAIL** Default translation "
1141 "string for option %s contains 8-bit "
1148 for (j
= 0; j
< option
->num_choices
; j
++)
1151 * Check for special characters outside A0 to BF, F7, or F8
1152 * that are used for languages other than English.
1155 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1156 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1157 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1162 if (!errors
&& !verbose
)
1163 _cupsLangPuts(stdout
, _(" FAIL\n"));
1166 _cupsLangPrintf(stdout
,
1167 _(" **FAIL** Default translation "
1168 "string for option %s choice %s contains "
1169 "8-bit characters!\n"),
1171 option
->choices
[j
].choice
);
1181 * Final pass/fail notification...
1185 status
= ERROR_CONFORMANCE
;
1187 _cupsLangPuts(stdout
, _(" PASS\n"));
1191 check_basics(argv
[i
]);
1193 if (warn
& WARN_CONSTRAINTS
)
1194 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1196 if (warn
& WARN_DEFAULTS
)
1197 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1199 if (warn
& WARN_FILTERS
)
1200 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1202 if (warn
& WARN_TRANSLATIONS
)
1203 errors
= check_translations(ppd
, errors
, verbose
, 1);
1206 * Look for default keywords with no corresponding option...
1209 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1211 attr
= ppd
->attrs
[j
];
1213 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1214 !strcmp(attr
->name
, "DefaultColorSep") ||
1215 !strcmp(attr
->name
, "DefaultFont") ||
1216 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1217 !strcmp(attr
->name
, "DefaultImageableArea") ||
1218 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1219 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1220 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1221 !strcmp(attr
->name
, "DefaultResolution") ||
1222 !strcmp(attr
->name
, "DefaultScreenProc") ||
1223 !strcmp(attr
->name
, "DefaultTransfer"))
1226 if (!strncmp(attr
->name
, "Default", 7) &&
1227 !ppdFindOption(ppd
, attr
->name
+ 7))
1228 _cupsLangPrintf(stdout
,
1229 _(" WARN %s has no corresponding "
1235 * Check for old Duplex option names...
1238 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1239 option
= ppdFindOption(ppd
, "KD03Duplex");
1243 _cupsLangPrintf(stdout
,
1244 _(" WARN Duplex option keyword %s "
1245 "should be named Duplex or JCLDuplex!\n"
1246 " REF: Page 122, section 5.17\n"),
1250 ppdMarkDefaults(ppd
);
1251 if (ppdConflicts(ppd
))
1253 _cupsLangPuts(stdout
,
1254 _(" WARN Default choices conflicting!\n"));
1256 show_conflicts(ppd
);
1259 if (ppdversion
< 43)
1261 _cupsLangPrintf(stdout
,
1262 _(" WARN Obsolete PPD version %.1f!\n"
1263 " REF: Page 42, section 5.2.\n"),
1267 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1269 _cupsLangPuts(stdout
,
1270 _(" WARN LanguageEncoding required by PPD "
1272 " REF: Pages 56-57, section 5.3.\n"));
1275 if (!ppd
->manufacturer
&& ppdversion
< 43)
1277 _cupsLangPuts(stdout
,
1278 _(" WARN Manufacturer required by PPD "
1280 " REF: Pages 58-59, section 5.3.\n"));
1284 * Treat a PCFileName attribute longer than 12 characters as
1285 * a warning and not a hard error...
1288 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1290 _cupsLangPuts(stdout
,
1291 _(" WARN PCFileName longer than 8.3 in "
1292 "violation of PPD spec.\n"
1293 " REF: Pages 61-62, section 5.3.\n"));
1296 if (!ppd
->shortnickname
&& ppdversion
< 43)
1298 _cupsLangPuts(stdout
,
1299 _(" WARN ShortNickName required by PPD "
1301 " REF: Pages 64-65, section 5.3.\n"));
1305 * Check the Protocols line and flag PJL + BCP since TBCP is
1306 * usually used with PJL...
1311 if (strstr(ppd
->protocols
, "PJL") &&
1312 strstr(ppd
->protocols
, "BCP") &&
1313 !strstr(ppd
->protocols
, "TBCP"))
1315 _cupsLangPuts(stdout
,
1316 _(" WARN Protocols contains both PJL "
1317 "and BCP; expected TBCP.\n"
1318 " REF: Pages 78-79, section 5.7.\n"));
1321 if (strstr(ppd
->protocols
, "PJL") &&
1322 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1324 _cupsLangPuts(stdout
,
1325 _(" WARN Protocols contains PJL but JCL "
1326 "attributes are not set.\n"
1327 " REF: Pages 78-79, section 5.7.\n"));
1332 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1333 * which are errors according to the spec but won't cause problems
1334 * with CUPS specifically...
1337 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1338 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1340 len
= strlen(option
->keyword
);
1342 for (m
= 0, group2
= ppd
->groups
;
1343 m
< ppd
->num_groups
;
1345 for (n
= 0, option2
= group2
->options
;
1346 n
< group2
->num_options
;
1348 if (option
!= option2
&&
1349 len
< strlen(option2
->keyword
) &&
1350 !strncmp(option
->keyword
, option2
->keyword
, len
))
1352 _cupsLangPrintf(stdout
,
1353 _(" WARN %s shares a common "
1355 " REF: Page 15, section "
1357 option
->keyword
, option2
->keyword
);
1366 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
1368 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
1372 if (attr
->value
[0] == '/')
1373 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, attr
->value
);
1376 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
1379 if (*ptr
== '/' || !*root
)
1380 snprintf(pathprog
, sizeof(pathprog
), "%s%s/profiles/%s", root
,
1383 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/profiles/%s", root
,
1388 if (!attr
->value
|| !attr
->value
[0] || stat(pathprog
, &statbuf
))
1391 _cupsLangPrintf(stdout
,
1392 _(" WARN Missing cupsICCProfile "
1394 !attr
->value
|| !attr
->value
[0] ? "<NULL>" :
1404 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
1406 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
1408 if ((!attr
->value
|| stat(attr
->value
, &statbuf
)) && verbose
>= 0)
1409 _cupsLangPrintf(stdout
, _(" WARN Missing "
1410 "APDialogExtension file \"%s\"\n"),
1411 attr
->value
? attr
->value
: "<NULL>");
1418 for (attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
);
1420 attr
= ppdFindNextAttr(ppd
, "APPrinterIconPath", NULL
))
1422 if ((!attr
->value
|| stat(attr
->value
, &statbuf
)) && verbose
>= 0)
1423 _cupsLangPrintf(stdout
, _(" WARN Missing "
1424 "APPrinterIconPath file \"%s\"\n"),
1425 attr
->value
? attr
->value
: "<NULL>");
1427 #endif /* __APPLE__ */
1432 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1434 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1438 * Then list the options, if "-v" was provided...
1443 _cupsLangPrintf(stdout
,
1445 " language_level = %d\n"
1446 " color_device = %s\n"
1447 " variable_sizes = %s\n"
1448 " landscape = %d\n",
1449 ppd
->language_level
,
1450 ppd
->color_device
? "TRUE" : "FALSE",
1451 ppd
->variable_sizes
? "TRUE" : "FALSE",
1454 switch (ppd
->colorspace
)
1457 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1460 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1463 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1466 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1469 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1473 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1474 ppd
->num_emulations
);
1475 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1476 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1477 j
, ppd
->emulations
[j
].name
);
1479 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1480 ppd
->lang_encoding
);
1481 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1483 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1484 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1485 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1486 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1488 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1489 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1490 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1491 ppd
->shortnickname
);
1492 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1493 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1495 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1496 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1498 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1501 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1503 _cupsLangPrintf(stdout
,
1504 " options[%d] = %s (%s) %s %s %.0f "
1506 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1507 sections
[option
->section
], option
->order
,
1508 option
->num_choices
);
1510 if (!strcmp(option
->keyword
, "PageSize") ||
1511 !strcmp(option
->keyword
, "PageRegion"))
1513 for (m
= option
->num_choices
, choice
= option
->choices
;
1517 size
= ppdPageSize(ppd
, choice
->choice
);
1520 _cupsLangPrintf(stdout
,
1522 choice
->choice
, choice
->text
);
1524 _cupsLangPrintf(stdout
,
1525 " %s (%s) = %.2fx%.2fin "
1526 "(%.1f,%.1f,%.1f,%.1f)",
1527 choice
->choice
, choice
->text
,
1528 size
->width
/ 72.0, size
->length
/ 72.0,
1529 size
->left
/ 72.0, size
->bottom
/ 72.0,
1530 size
->right
/ 72.0, size
->top
/ 72.0);
1532 if (!strcmp(option
->defchoice
, choice
->choice
))
1533 _cupsLangPuts(stdout
, " *\n");
1535 _cupsLangPuts(stdout
, "\n");
1540 for (m
= option
->num_choices
, choice
= option
->choices
;
1544 _cupsLangPrintf(stdout
, " %s (%s)",
1545 choice
->choice
, choice
->text
);
1547 if (!strcmp(option
->defchoice
, choice
->choice
))
1548 _cupsLangPuts(stdout
, " *\n");
1550 _cupsLangPuts(stdout
, "\n");
1556 _cupsLangPrintf(stdout
, " num_consts = %d\n",
1558 for (j
= 0; j
< ppd
->num_consts
; j
++)
1559 _cupsLangPrintf(stdout
,
1560 " consts[%d] = *%s %s *%s %s\n",
1561 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1562 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1564 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1566 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1567 _cupsLangPrintf(stdout
,
1568 " profiles[%d] = %s/%s %.3f %.3f "
1569 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1570 j
, ppd
->profiles
[j
].resolution
,
1571 ppd
->profiles
[j
].media_type
,
1572 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1573 ppd
->profiles
[j
].matrix
[0][0],
1574 ppd
->profiles
[j
].matrix
[0][1],
1575 ppd
->profiles
[j
].matrix
[0][2],
1576 ppd
->profiles
[j
].matrix
[1][0],
1577 ppd
->profiles
[j
].matrix
[1][1],
1578 ppd
->profiles
[j
].matrix
[1][2],
1579 ppd
->profiles
[j
].matrix
[2][0],
1580 ppd
->profiles
[j
].matrix
[2][1],
1581 ppd
->profiles
[j
].matrix
[2][2]);
1583 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1584 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1585 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1588 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1589 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1590 _cupsLangPrintf(stdout
,
1591 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1592 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1593 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1594 ppd
->attrs
[j
]->text
,
1595 ppd
->attrs
[j
]->value
?
1596 ppd
->attrs
[j
]->value
: "(null)");
1610 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1614 check_basics(const char *filename
) /* I - PPD file to check */
1616 cups_file_t
*fp
; /* File pointer */
1617 int ch
; /* Current character */
1618 int col
, /* Current column */
1619 whitespace
; /* Only seen whitespace? */
1620 int eol
; /* Line endings */
1621 int linenum
; /* Line number */
1622 int mixed
; /* Mixed line endings? */
1625 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1634 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1636 if (ch
== '\r' || ch
== '\n')
1640 if (eol
== EOL_NONE
)
1642 else if (eol
!= EOL_LF
)
1645 else if (ch
== '\r')
1647 if (cupsFilePeekChar(fp
) == '\n')
1649 cupsFileGetChar(fp
);
1651 if (eol
== EOL_NONE
)
1656 else if (eol
== EOL_NONE
)
1662 if (col
> 0 && whitespace
)
1663 _cupsLangPrintf(stdout
,
1664 _(" WARN Line %d only contains whitespace!\n"),
1673 if (ch
!= ' ' && ch
!= '\t')
1681 _cupsLangPuts(stdout
,
1682 _(" WARN File contains a mix of CR, LF, and "
1683 "CR LF line endings!\n"));
1685 if (eol
== EOL_CRLF
)
1686 _cupsLangPuts(stdout
,
1687 _(" WARN Non-Windows PPD files should use lines "
1688 "ending with only LF, not CR LF!\n"));
1695 * 'check_constraints()' - Check UIConstraints in the PPD file.
1698 static int /* O - Errors found */
1699 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1700 int errors
, /* I - Errors found */
1701 int verbose
, /* I - Verbosity level */
1702 int warn
) /* I - Warnings only? */
1704 int j
; /* Looping var */
1705 ppd_const_t
*c
; /* Current constraint */
1706 ppd_option_t
*option
; /* Standard UI option */
1707 ppd_option_t
*option2
; /* Standard UI option */
1708 const char *prefix
; /* WARN/FAIL prefix */
1711 prefix
= warn
? " WARN " : "**FAIL**";
1713 for (j
= ppd
->num_consts
, c
= ppd
->consts
; j
> 0; j
--, c
++)
1715 option
= ppdFindOption(ppd
, c
->option1
);
1716 option2
= ppdFindOption(ppd
, c
->option2
);
1718 if (!option
|| !option2
)
1720 if (!warn
&& !errors
&& !verbose
)
1721 _cupsLangPuts(stdout
, _(" FAIL\n"));
1724 _cupsLangPrintf(stdout
,
1725 _(" %s Missing option %s in "
1726 "UIConstraint \"*%s %s *%s %s\"!\n"),
1728 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1731 _cupsLangPrintf(stdout
,
1732 _(" %s Missing option %s in "
1733 "UIConstraint \"*%s %s *%s %s\"!\n"),
1735 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1743 if (c
->choice1
[0] && !ppdFindChoice(option
, c
->choice1
))
1745 if (!warn
&& !errors
&& !verbose
)
1746 _cupsLangPuts(stdout
, _(" FAIL\n"));
1748 _cupsLangPrintf(stdout
,
1749 _(" %s Missing choice *%s %s in "
1750 "UIConstraint \"*%s %s *%s %s\"!\n"),
1751 prefix
, c
->option1
, c
->choice1
,
1752 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1758 if (c
->choice2
[0] && !ppdFindChoice(option2
, c
->choice2
))
1760 if (!warn
&& !errors
&& !verbose
)
1761 _cupsLangPuts(stdout
, _(" FAIL\n"));
1763 _cupsLangPrintf(stdout
,
1764 _(" %s Missing choice *%s %s in "
1765 "UIConstraint \"*%s %s *%s %s\"!\n"),
1766 prefix
, c
->option2
, c
->choice2
,
1767 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1779 * 'check_defaults()' - Check default option keywords in the PPD file.
1782 static int /* O - Errors found */
1783 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
1784 int errors
, /* I - Errors found */
1785 int verbose
, /* I - Verbosity level */
1786 int warn
) /* I - Warnings only? */
1788 int j
, k
; /* Looping vars */
1789 ppd_attr_t
*attr
; /* PPD attribute */
1790 ppd_option_t
*option
; /* Standard UI option */
1791 const char *prefix
; /* WARN/FAIL prefix */
1794 prefix
= warn
? " WARN " : "**FAIL**";
1796 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1798 attr
= ppd
->attrs
[j
];
1800 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1801 !strcmp(attr
->name
, "DefaultFont") ||
1802 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1803 !strcmp(attr
->name
, "DefaultImageableArea") ||
1804 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1805 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1806 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1807 !strcmp(attr
->name
, "DefaultResolution") ||
1808 !strcmp(attr
->name
, "DefaultTransfer"))
1811 if (!strncmp(attr
->name
, "Default", 7))
1813 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
1814 strcmp(attr
->value
, "Unknown"))
1817 * Check that the default option value matches a choice...
1820 for (k
= 0; k
< option
->num_choices
; k
++)
1821 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
1824 if (k
>= option
->num_choices
)
1826 if (!warn
&& !errors
&& !verbose
)
1827 _cupsLangPuts(stdout
, _(" FAIL\n"));
1830 _cupsLangPrintf(stdout
,
1831 _(" %s %s %s does not exist!\n"),
1832 prefix
, attr
->name
, attr
->value
);
1846 * 'check_filters()' - Check filters in the PPD file.
1849 static int /* O - Errors found */
1850 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
1851 const char *root
, /* I - Root directory */
1852 int errors
, /* I - Errors found */
1853 int verbose
, /* I - Verbosity level */
1854 int warn
) /* I - Warnings only? */
1856 ppd_attr_t
*attr
; /* PPD attribute */
1857 const char *ptr
; /* Pointer into string */
1858 struct stat statbuf
; /* File information */
1859 char super
[16], /* Super-type for filter */
1860 type
[256], /* Type for filter */
1861 program
[256], /* Program/filter name */
1862 pathprog
[1024]; /* Complete path to program/filter */
1863 int cost
; /* Cost of filter */
1864 const char *prefix
; /* WARN/FAIL prefix */
1867 prefix
= warn
? " WARN " : "**FAIL**";
1869 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
1871 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
1874 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1877 if (!warn
&& !errors
&& !verbose
)
1878 _cupsLangPuts(stdout
, _(" FAIL\n"));
1881 _cupsLangPrintf(stdout
,
1882 _(" %s Bad cupsFilter value \"%s\"!\n"),
1883 prefix
, attr
->value
? attr
->value
: "");
1890 if (program
[0] == '/')
1891 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1894 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1895 ptr
= CUPS_SERVERBIN
;
1897 if (*ptr
== '/' || !*root
)
1898 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1901 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1905 if (stat(pathprog
, &statbuf
))
1907 if (!warn
&& !errors
&& !verbose
)
1908 _cupsLangPuts(stdout
, _(" FAIL\n"));
1911 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
1912 "file \"%s\"\n"), prefix
, program
);
1920 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
1922 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
1925 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1928 if (!warn
&& !errors
&& !verbose
)
1929 _cupsLangPuts(stdout
, _(" FAIL\n"));
1932 _cupsLangPrintf(stdout
,
1933 _(" %s Bad cupsPreFilter value \"%s\"!\n"),
1934 prefix
, attr
->value
? attr
->value
: "");
1941 if (program
[0] == '/')
1942 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1945 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1946 ptr
= CUPS_SERVERBIN
;
1948 if (*ptr
== '/' || !*root
)
1949 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1952 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1956 if (stat(pathprog
, &statbuf
))
1958 if (!warn
&& !errors
&& !verbose
)
1959 _cupsLangPuts(stdout
, _(" FAIL\n"));
1962 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
1963 "file \"%s\"\n"), prefix
, program
);
1976 * 'check_translations()' - Check translations in the PPD file.
1979 static int /* O - Errors found */
1980 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
1981 int errors
, /* I - Errors found */
1982 int verbose
, /* I - Verbosity level */
1983 int warn
) /* I - Warnings only? */
1985 int j
; /* Looping var */
1986 ppd_attr_t
*attr
; /* PPD attribute */
1987 char *languages
, /* Copy of attribute value */
1988 *langstart
, /* Start of current language */
1989 *langptr
, /* Pointer into languages */
1990 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
1991 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
1992 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
1993 cllkeyword
[PPD_MAX_NAME
];
1994 /* Custom option keyword (base) */
1995 ppd_option_t
*option
; /* Standard UI option */
1996 ppd_coption_t
*coption
; /* Custom option */
1997 ppd_cparam_t
*cparam
; /* Custom parameter */
1998 cups_array_t
*langlist
; /* List of languages so far */
1999 char ll
[3]; /* Base language */
2000 const char *prefix
; /* WARN/FAIL prefix */
2003 prefix
= warn
? " WARN " : "**FAIL**";
2005 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
2009 * This file contains localizations, check them...
2012 languages
= strdup(attr
->value
);
2013 langlist
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
2015 for (langptr
= languages
; *langptr
;)
2018 * Skip leading whitespace...
2021 while (isspace(*langptr
& 255))
2028 * Find the end of this language name...
2031 for (langstart
= langptr
;
2032 *langptr
&& !isspace(*langptr
& 255);
2038 j
= strlen(langstart
);
2039 if (j
!= 2 && j
!= 5)
2041 if (!warn
&& !errors
&& !verbose
)
2042 _cupsLangPuts(stdout
, _(" FAIL\n"));
2045 _cupsLangPrintf(stdout
,
2046 _(" %s Bad language \"%s\"!\n"),
2055 cupsArrayAdd(langlist
, langstart
);
2057 strlcpy(ll
, langstart
, sizeof(ll
));
2060 * Loop through all options and choices...
2063 for (option
= ppdFirstOption(ppd
);
2065 option
= ppdNextOption(ppd
))
2067 if (!strcmp(option
->keyword
, "PageRegion"))
2070 snprintf(keyword
, sizeof(keyword
), "%s.Translation", langstart
);
2071 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
2073 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
2074 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
2076 if (!warn
&& !errors
&& !verbose
)
2077 _cupsLangPuts(stdout
, _(" FAIL\n"));
2080 _cupsLangPrintf(stdout
,
2081 _(" %s Missing \"%s\" translation "
2082 "string for option %s!\n"),
2083 prefix
, langstart
, option
->keyword
);
2088 else if (!valid_utf8(attr
->text
))
2090 if (!warn
&& !errors
&& !verbose
)
2091 _cupsLangPuts(stdout
, _(" FAIL\n"));
2094 _cupsLangPrintf(stdout
,
2095 _(" %s Bad UTF-8 \"%s\" translation "
2096 "string for option %s!\n"),
2097 prefix
, langstart
, option
->keyword
);
2103 snprintf(keyword
, sizeof(keyword
), "%s.%s", langstart
,
2105 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
2108 for (j
= 0; j
< option
->num_choices
; j
++)
2110 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
2111 (coption
= ppdFindCustomOption(ppd
,
2112 option
->keyword
)) != NULL
)
2114 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
2115 langstart
, option
->keyword
);
2117 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
2118 !valid_utf8(attr
->text
))
2120 if (!warn
&& !errors
&& !verbose
)
2121 _cupsLangPuts(stdout
, _(" FAIL\n"));
2124 _cupsLangPrintf(stdout
,
2125 _(" %s Bad UTF-8 \"%s\" "
2126 "translation string for option %s, "
2129 ckeyword
+ 1 + strlen(langstart
),
2136 if (strcasecmp(option
->keyword
, "PageSize"))
2138 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
2140 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
2142 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
2143 langstart
, option
->keyword
);
2144 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
2145 ll
, option
->keyword
);
2147 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
2148 cparam
->name
)) == NULL
&&
2149 (attr
= ppdFindAttr(ppd
, cllkeyword
,
2150 cparam
->name
)) == NULL
)
2152 if (!warn
&& !errors
&& !verbose
)
2153 _cupsLangPuts(stdout
, _(" FAIL\n"));
2156 _cupsLangPrintf(stdout
,
2157 _(" %s Missing \"%s\" "
2158 "translation string for option %s, "
2161 ckeyword
+ 1 + strlen(langstart
),
2167 else if (!valid_utf8(attr
->text
))
2169 if (!warn
&& !errors
&& !verbose
)
2170 _cupsLangPuts(stdout
, _(" FAIL\n"));
2173 _cupsLangPrintf(stdout
,
2174 _(" %s Bad UTF-8 \"%s\" "
2175 "translation string for option %s, "
2178 ckeyword
+ 1 + strlen(langstart
),
2187 else if ((attr
= ppdFindAttr(ppd
, keyword
,
2188 option
->choices
[j
].choice
)) == NULL
&&
2189 (attr
= ppdFindAttr(ppd
, llkeyword
,
2190 option
->choices
[j
].choice
)) == NULL
)
2192 if (!warn
&& !errors
&& !verbose
)
2193 _cupsLangPuts(stdout
, _(" FAIL\n"));
2196 _cupsLangPrintf(stdout
,
2197 _(" %s Missing \"%s\" "
2198 "translation string for option %s, "
2200 prefix
, langstart
, option
->keyword
,
2201 option
->choices
[j
].choice
);
2206 else if (!valid_utf8(attr
->text
))
2208 if (!warn
&& !errors
&& !verbose
)
2209 _cupsLangPuts(stdout
, _(" FAIL\n"));
2212 _cupsLangPrintf(stdout
,
2213 _(" %s Bad UTF-8 \"%s\" "
2214 "translation string for option %s, "
2216 prefix
, langstart
, option
->keyword
,
2217 option
->choices
[j
].choice
);
2227 * Verify that we have the base language for each localized one...
2230 for (langptr
= (char *)cupsArrayFirst(langlist
);
2232 langptr
= (char *)cupsArrayNext(langlist
))
2236 * Lookup the base language...
2239 cupsArraySave(langlist
);
2241 strlcpy(ll
, langptr
, sizeof(ll
));
2243 if (!cupsArrayFind(langlist
, ll
) && strcmp(ll
, "zh"))
2245 if (!warn
&& !errors
&& !verbose
)
2246 _cupsLangPuts(stdout
, _(" FAIL\n"));
2249 _cupsLangPrintf(stdout
,
2250 _(" %s No base translation \"%s\" "
2251 "is included in file!\n"), prefix
, ll
);
2257 cupsArrayRestore(langlist
);
2261 * Free memory used for the languages...
2264 cupsArrayDelete(langlist
);
2273 * 'show_conflicts()' - Show option conflicts in a PPD file.
2277 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
2279 int i
, j
; /* Looping variables */
2280 ppd_const_t
*c
; /* Current constraint */
2281 ppd_option_t
*o1
, *o2
; /* Options */
2282 ppd_choice_t
*c1
, *c2
; /* Choices */
2286 * Loop through all of the UI constraints and report any options
2290 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
2293 * Grab pointers to the first option...
2296 o1
= ppdFindOption(ppd
, c
->option1
);
2300 else if (c
->choice1
[0] != '\0')
2303 * This constraint maps to a specific choice.
2306 c1
= ppdFindChoice(o1
, c
->choice1
);
2311 * This constraint applies to any choice for this option.
2314 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
2319 !strcasecmp(c1
->choice
, "None") ||
2320 !strcasecmp(c1
->choice
, "Off") ||
2321 !strcasecmp(c1
->choice
, "False"))
2326 * Grab pointers to the second option...
2329 o2
= ppdFindOption(ppd
, c
->option2
);
2333 else if (c
->choice2
[0] != '\0')
2336 * This constraint maps to a specific choice.
2339 c2
= ppdFindChoice(o2
, c
->choice2
);
2344 * This constraint applies to any choice for this option.
2347 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
2352 !strcasecmp(c2
->choice
, "None") ||
2353 !strcasecmp(c2
->choice
, "Off") ||
2354 !strcasecmp(c2
->choice
, "False"))
2359 * If both options are marked then there is a conflict...
2362 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
2363 _cupsLangPrintf(stdout
,
2364 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
2365 " (constraint=\"%s %s %s %s\")\n"),
2366 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
2367 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2373 * 'test_raster()' - Test PostScript commands for raster printers.
2376 static int /* O - 1 on success, 0 on failure */
2377 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
2378 int verbose
) /* I - Verbosity */
2380 cups_page_header2_t header
; /* Page header */
2383 ppdMarkDefaults(ppd
);
2384 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
2387 _cupsLangPuts(stdout
, _(" FAIL\n"));
2390 _cupsLangPrintf(stdout
,
2391 _(" **FAIL** Default option code cannot be "
2392 "interpreted: %s\n"), cupsRasterErrorString());
2398 * Try a test of custom page size code, if available...
2401 if (!ppdPageSize(ppd
, "Custom.612x792"))
2404 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
2406 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
2409 _cupsLangPuts(stdout
, _(" FAIL\n"));
2412 _cupsLangPrintf(stdout
,
2413 _(" **FAIL** Default option code cannot be "
2414 "interpreted: %s\n"), cupsRasterErrorString());
2424 * 'usage()' - Show program usage...
2430 _cupsLangPuts(stdout
,
2431 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
2432 "[... filenameN.ppd[.gz]]\n"
2433 " program | cupstestppd [options] -\n"
2437 " -R root-directory Set alternate root\n"
2438 " -W {all,none,constraints,defaults,filters,translations}\n"
2439 " Issue warnings instead of errors\n"
2440 " -q Run silently\n"
2441 " -r Use 'relaxed' open mode\n"
2442 " -v Be slightly verbose\n"
2443 " -vv Be very verbose\n"));
2450 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
2453 static int /* O - 1 if valid, 0 if not */
2454 valid_utf8(const char *s
) /* I - String to check */
2461 * Check for valid UTF-8 sequence...
2464 if ((*s
& 0xc0) == 0x80)
2465 return (0); /* Illegal suffix byte */
2466 else if ((*s
& 0xe0) == 0xc0)
2469 * 2-byte sequence...
2474 if ((*s
& 0xc0) != 0x80)
2475 return (0); /* Missing suffix byte */
2477 else if ((*s
& 0xf0) == 0xe0)
2480 * 3-byte sequence...
2485 if ((*s
& 0xc0) != 0x80)
2486 return (0); /* Missing suffix byte */
2490 if ((*s
& 0xc0) != 0x80)
2491 return (0); /* Missing suffix byte */
2493 else if ((*s
& 0xf8) == 0xf0)
2496 * 4-byte sequence...
2501 if ((*s
& 0xc0) != 0x80)
2502 return (0); /* Missing suffix byte */
2506 if ((*s
& 0xc0) != 0x80)
2507 return (0); /* Missing suffix byte */
2511 if ((*s
& 0xc0) != 0x80)
2512 return (0); /* Missing suffix byte */
2515 return (0); /* Bad sequence */