2 * "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $"
4 * PPD test program for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 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/string.h>
45 #include <cups/cups.h>
47 #include <cups/ppd-private.h>
48 #include <cups/i18n.h>
49 #include <cups/raster.h>
56 * Error warning overrides...
66 WARN_TRANSLATIONS
= 16,
101 * Standard Adobe media keywords (must remain sorted)...
104 static const char adobe_size_names
[][PPD_MAX_NAME
] =
165 "DoublePostcardRotated",
220 "FanFoldGermanLegal",
266 static void check_basics(const char *filename
);
267 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
269 static int check_case(ppd_file_t
*ppd
, int errors
, int verbose
);
270 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
272 static int check_duplex(ppd_file_t
*ppd
, int errors
, int verbose
,
274 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
275 int verbose
, int warn
);
276 static int check_profiles(ppd_file_t
*ppd
, const char *root
, int errors
,
277 int verbose
, int warn
);
278 static int check_sizes(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
279 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,
281 static void show_conflicts(ppd_file_t
*ppd
);
282 static int test_raster(ppd_file_t
*ppd
, int verbose
);
283 static void usage(void);
284 static int valid_path(const char *keyword
, const char *path
, int errors
,
285 int verbose
, int warn
);
286 static int valid_utf8(const char *s
);
290 * 'main()' - Main entry for test program.
293 int /* O - Exit status */
294 main(int argc
, /* I - Number of command-line args */
295 char *argv
[]) /* I - Command-line arguments */
297 int i
, j
, k
, m
, n
; /* Looping vars */
298 int len
; /* Length of option name */
299 char *opt
; /* Option character */
300 const char *ptr
; /* Pointer into string */
301 int files
; /* Number of files */
302 int verbose
; /* Want verbose output? */
303 int warn
; /* Which errors to just warn about */
304 int status
; /* Exit status */
305 int errors
; /* Number of conformance errors */
306 int ppdversion
; /* PPD spec version in PPD file */
307 ppd_status_t error
; /* Status of ppdOpen*() */
308 int line
; /* Line number for error */
309 char *root
; /* Root directory */
310 int xdpi
, /* X resolution */
311 ydpi
; /* Y resolution */
312 ppd_file_t
*ppd
; /* PPD file record */
313 ppd_attr_t
*attr
; /* PPD attribute */
314 ppd_size_t
*size
; /* Size record */
315 ppd_group_t
*group
; /* UI group */
316 ppd_option_t
*option
; /* Standard UI option */
317 ppd_group_t
*group2
; /* UI group */
318 ppd_option_t
*option2
; /* Standard UI option */
319 ppd_choice_t
*choice
; /* Standard UI option choice */
320 struct lconv
*loc
; /* Locale data */
321 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
322 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
323 "JCL", "PAGE", "PROLOG" };
326 _cupsSetLocale(argv
);
330 * Display PPD files for each file listed on the command-line...
333 ppdSetConformance(PPD_CONFORM_STRICT
);
342 for (i
= 1; i
< argc
; i
++)
343 if (argv
[i
][0] == '-' && argv
[i
][1])
345 for (opt
= argv
[i
] + 1; *opt
; opt
++)
348 case 'R' : /* Alternate root directory */
357 case 'W' : /* Turn errors into warnings */
363 if (!strcmp(argv
[i
], "none"))
365 else if (!strcmp(argv
[i
], "constraints"))
366 warn
|= WARN_CONSTRAINTS
;
367 else if (!strcmp(argv
[i
], "defaults"))
368 warn
|= WARN_DEFAULTS
;
369 else if (!strcmp(argv
[i
], "duplex"))
371 else if (!strcmp(argv
[i
], "filters"))
372 warn
|= WARN_FILTERS
;
373 else if (!strcmp(argv
[i
], "profiles"))
374 warn
|= WARN_PROFILES
;
375 else if (!strcmp(argv
[i
], "sizes"))
377 else if (!strcmp(argv
[i
], "translations"))
378 warn
|= WARN_TRANSLATIONS
;
379 else if (!strcmp(argv
[i
], "all"))
385 case 'q' : /* Quiet mode */
388 _cupsLangPuts(stderr
,
389 _("cupstestppd: The -q option is incompatible "
390 "with the -v option.\n"));
397 case 'r' : /* Relaxed mode */
398 ppdSetConformance(PPD_CONFORM_RELAXED
);
401 case 'v' : /* Verbose mode */
404 _cupsLangPuts(stderr
,
405 _("cupstestppd: The -v option is incompatible "
406 "with the -q option.\n"));
421 * Open the PPD file...
424 if (files
&& verbose
>= 0)
425 _cupsLangPuts(stdout
, "\n");
429 if (argv
[i
][0] == '-')
435 ppd
= ppdOpen(stdin
);
438 printf("%s:", (ppd
&& ppd
->pcfilename
) ? ppd
->pcfilename
: "(stdin)");
443 * Read from a file...
447 printf("%s:", argv
[i
]);
449 ppd
= ppdOpenFile(argv
[i
]);
454 error
= ppdLastError(&line
);
456 if (error
<= PPD_ALLOC_ERROR
)
458 status
= ERROR_FILE_OPEN
;
461 _cupsLangPrintf(stdout
,
463 " **FAIL** Unable to open PPD file - %s\n"),
468 status
= ERROR_PPD_FORMAT
;
472 _cupsLangPrintf(stdout
,
474 " **FAIL** Unable to open PPD file - "
476 ppdErrorString(error
), line
);
480 case PPD_MISSING_PPDADOBE4
:
481 _cupsLangPuts(stdout
,
482 _(" REF: Page 42, section 5.2.\n"));
484 case PPD_MISSING_VALUE
:
485 _cupsLangPuts(stdout
,
486 _(" REF: Page 20, section 3.4.\n"));
488 case PPD_BAD_OPEN_GROUP
:
489 case PPD_NESTED_OPEN_GROUP
:
490 _cupsLangPuts(stdout
,
491 _(" REF: Pages 45-46, section 5.2.\n"));
493 case PPD_BAD_OPEN_UI
:
494 case PPD_NESTED_OPEN_UI
:
495 _cupsLangPuts(stdout
,
496 _(" REF: Pages 42-45, section 5.2.\n"));
498 case PPD_BAD_ORDER_DEPENDENCY
:
499 _cupsLangPuts(stdout
,
500 _(" REF: Pages 48-49, section 5.2.\n"));
502 case PPD_BAD_UI_CONSTRAINTS
:
503 _cupsLangPuts(stdout
,
504 _(" REF: Pages 52-54, section 5.2.\n"));
506 case PPD_MISSING_ASTERISK
:
507 _cupsLangPuts(stdout
,
508 _(" REF: Page 15, section 3.2.\n"));
510 case PPD_LINE_TOO_LONG
:
511 _cupsLangPuts(stdout
,
512 _(" REF: Page 15, section 3.1.\n"));
514 case PPD_ILLEGAL_CHARACTER
:
515 _cupsLangPuts(stdout
,
516 _(" REF: Page 15, section 3.1.\n"));
518 case PPD_ILLEGAL_MAIN_KEYWORD
:
519 _cupsLangPuts(stdout
,
520 _(" REF: Pages 16-17, section 3.2.\n"));
522 case PPD_ILLEGAL_OPTION_KEYWORD
:
523 _cupsLangPuts(stdout
,
524 _(" REF: Page 19, section 3.3.\n"));
526 case PPD_ILLEGAL_TRANSLATION
:
527 _cupsLangPuts(stdout
,
528 _(" REF: Page 27, section 3.5.\n"));
534 check_basics(argv
[i
]);
542 * Show the header and then perform basic conformance tests (limited
543 * only by what the CUPS PPD functions actually load...)
550 _cupsLangPuts(stdout
,
551 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
553 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
555 ppdversion
= (int)(10 * _cupsStrScand(attr
->value
, NULL
, loc
) + 0.5);
557 for (j
= 0; j
< ppd
->num_filters
; j
++)
558 if (strstr(ppd
->filters
[j
], "application/vnd.cups-raster"))
560 if (!test_raster(ppd
, verbose
))
566 * Look for default keywords with no matching option...
569 if (!(warn
& WARN_DEFAULTS
))
570 errors
= check_defaults(ppd
, errors
, verbose
, 0);
572 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
576 if (!errors
&& !verbose
)
577 _cupsLangPuts(stdout
, _(" FAIL\n"));
579 _cupsLangPuts(stdout
,
580 _(" **FAIL** REQUIRED DefaultImageableArea\n"
581 " REF: Page 102, section 5.15.\n"));
586 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
587 strcmp(attr
->value
, "Unknown"))
591 if (!errors
&& !verbose
)
592 _cupsLangPuts(stdout
, _(" FAIL\n"));
594 _cupsLangPrintf(stdout
,
595 _(" **FAIL** BAD DefaultImageableArea %s!\n"
596 " REF: Page 102, section 5.15.\n"),
605 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
608 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
612 if (!errors
&& !verbose
)
613 _cupsLangPuts(stdout
, _(" FAIL\n"));
615 _cupsLangPuts(stdout
,
616 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
617 " REF: Page 103, section 5.15.\n"));
622 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
623 strcmp(attr
->value
, "Unknown"))
627 if (!errors
&& !verbose
)
628 _cupsLangPuts(stdout
, _(" FAIL\n"));
630 _cupsLangPrintf(stdout
,
631 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
632 " REF: Page 103, section 5.15.\n"),
638 else if (verbose
> 0)
639 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
641 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
642 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
645 * Verify that we have a default choice...
648 if (option
->defchoice
[0])
650 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
651 strcmp(option
->defchoice
, "Unknown"))
655 if (!errors
&& !verbose
)
656 _cupsLangPuts(stdout
, _(" FAIL\n"));
658 _cupsLangPrintf(stdout
,
659 _(" **FAIL** BAD Default%s %s\n"
660 " REF: Page 40, section 4.5.\n"),
661 option
->keyword
, option
->defchoice
);
666 else if (verbose
> 0)
667 _cupsLangPrintf(stdout
,
668 _(" PASS Default%s\n"),
675 if (!errors
&& !verbose
)
676 _cupsLangPuts(stdout
, _(" FAIL\n"));
678 _cupsLangPrintf(stdout
,
679 _(" **FAIL** REQUIRED Default%s\n"
680 " REF: Page 40, section 4.5.\n"),
688 if ((attr
= ppdFindAttr(ppd
, "FileVersion", NULL
)) != NULL
)
690 for (ptr
= attr
->value
; *ptr
; ptr
++)
691 if (!isdigit(*ptr
& 255) && *ptr
!= '.')
698 if (!errors
&& !verbose
)
699 _cupsLangPuts(stdout
, _(" FAIL\n"));
701 _cupsLangPrintf(stdout
,
702 _(" **FAIL** Bad FileVersion \"%s\"\n"
703 " REF: Page 56, section 5.3.\n"),
709 else if (verbose
> 0)
710 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
716 if (!errors
&& !verbose
)
717 _cupsLangPuts(stdout
, _(" FAIL\n"));
719 _cupsLangPuts(stdout
,
720 _(" **FAIL** REQUIRED FileVersion\n"
721 " REF: Page 56, section 5.3.\n"));
727 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
)
730 if (*ptr
== '4' && ptr
[1] == '.')
733 for (ptr
+= 2; *ptr
; ptr
++)
734 if (!isdigit(*ptr
& 255))
742 if (!errors
&& !verbose
)
743 _cupsLangPuts(stdout
, _(" FAIL\n"));
745 _cupsLangPrintf(stdout
,
746 _(" **FAIL** Bad FormatVersion \"%s\"\n"
747 " REF: Page 56, section 5.3.\n"),
753 else if (verbose
> 0)
754 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
760 if (!errors
&& !verbose
)
761 _cupsLangPuts(stdout
, _(" FAIL\n"));
763 _cupsLangPuts(stdout
,
764 _(" **FAIL** REQUIRED FormatVersion\n"
765 " REF: Page 56, section 5.3.\n"));
771 if (ppd
->lang_encoding
!= NULL
)
774 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
776 else if (ppdversion
> 40)
780 if (!errors
&& !verbose
)
781 _cupsLangPuts(stdout
, _(" FAIL\n"));
783 _cupsLangPuts(stdout
,
784 _(" **FAIL** REQUIRED LanguageEncoding\n"
785 " REF: Pages 56-57, section 5.3.\n"));
791 if (ppd
->lang_version
!= NULL
)
794 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
800 if (!errors
&& !verbose
)
801 _cupsLangPuts(stdout
, _(" FAIL\n"));
803 _cupsLangPuts(stdout
,
804 _(" **FAIL** REQUIRED LanguageVersion\n"
805 " REF: Pages 57-58, section 5.3.\n"));
811 if (ppd
->manufacturer
!= NULL
)
813 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
814 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
818 if (!errors
&& !verbose
)
819 _cupsLangPuts(stdout
, _(" FAIL\n"));
821 _cupsLangPuts(stdout
,
822 _(" **FAIL** BAD Manufacturer (should be "
824 " REF: Page 211, table D.1.\n"));
829 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
830 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
834 if (!errors
&& !verbose
)
835 _cupsLangPuts(stdout
, _(" FAIL\n"));
837 _cupsLangPuts(stdout
,
838 _(" **FAIL** BAD Manufacturer (should be "
840 " REF: Page 211, table D.1.\n"));
845 else if (verbose
> 0)
846 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
848 else if (ppdversion
>= 43)
852 if (!errors
&& !verbose
)
853 _cupsLangPuts(stdout
, _(" FAIL\n"));
855 _cupsLangPuts(stdout
,
856 _(" **FAIL** REQUIRED Manufacturer\n"
857 " REF: Pages 58-59, section 5.3.\n"));
863 if (ppd
->modelname
!= NULL
)
865 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
866 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
873 if (!errors
&& !verbose
)
874 _cupsLangPuts(stdout
, _(" FAIL\n"));
876 _cupsLangPrintf(stdout
,
877 _(" **FAIL** BAD ModelName - \"%c\" not "
878 "allowed in string.\n"
879 " REF: Pages 59-60, section 5.3.\n"),
885 else if (verbose
> 0)
886 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
892 if (!errors
&& !verbose
)
893 _cupsLangPuts(stdout
, _(" FAIL\n"));
895 _cupsLangPuts(stdout
,
896 _(" **FAIL** REQUIRED ModelName\n"
897 " REF: Pages 59-60, section 5.3.\n"));
903 if (ppd
->nickname
!= NULL
)
906 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
912 if (!errors
&& !verbose
)
913 _cupsLangPuts(stdout
, _(" FAIL\n"));
915 _cupsLangPuts(stdout
,
916 _(" **FAIL** REQUIRED NickName\n"
917 " REF: Page 60, section 5.3.\n"));
923 if (ppdFindOption(ppd
, "PageSize") != NULL
)
926 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
932 if (!errors
&& !verbose
)
933 _cupsLangPuts(stdout
, _(" FAIL\n"));
935 _cupsLangPuts(stdout
,
936 _(" **FAIL** REQUIRED PageSize\n"
937 " REF: Pages 99-100, section 5.14.\n"));
943 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
946 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
952 if (!errors
&& !verbose
)
953 _cupsLangPuts(stdout
, _(" FAIL\n"));
955 _cupsLangPuts(stdout
,
956 _(" **FAIL** REQUIRED PageRegion\n"
957 " REF: Page 100, section 5.14.\n"));
963 if (ppd
->pcfilename
!= NULL
)
966 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
972 if (!errors
&& !verbose
)
973 _cupsLangPuts(stdout
, _(" FAIL\n"));
975 _cupsLangPuts(stdout
,
976 _(" **FAIL** REQUIRED PCFileName\n"
977 " REF: Pages 61-62, section 5.3.\n"));
983 if (ppd
->product
!= NULL
)
985 if (ppd
->product
[0] != '(' ||
986 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
990 if (!errors
&& !verbose
)
991 _cupsLangPuts(stdout
, _(" FAIL\n"));
993 _cupsLangPuts(stdout
,
994 _(" **FAIL** BAD Product - not \"(string)\".\n"
995 " REF: Page 62, section 5.3.\n"));
1000 else if (verbose
> 0)
1001 _cupsLangPuts(stdout
, _(" PASS Product\n"));
1007 if (!errors
&& !verbose
)
1008 _cupsLangPuts(stdout
, _(" FAIL\n"));
1010 _cupsLangPuts(stdout
,
1011 _(" **FAIL** REQUIRED Product\n"
1012 " REF: Page 62, section 5.3.\n"));
1018 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
1019 attr
->value
!= NULL
)
1021 char junkstr
[255]; /* Temp string */
1022 int junkint
; /* Temp integer */
1025 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
1029 if (!errors
&& !verbose
)
1030 _cupsLangPuts(stdout
, _(" FAIL\n"));
1032 _cupsLangPuts(stdout
,
1033 _(" **FAIL** BAD PSVersion - not \"(string) "
1035 " REF: Pages 62-64, section 5.3.\n"));
1040 else if (verbose
> 0)
1041 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
1047 if (!errors
&& !verbose
)
1048 _cupsLangPuts(stdout
, _(" FAIL\n"));
1050 _cupsLangPuts(stdout
,
1051 _(" **FAIL** REQUIRED PSVersion\n"
1052 " REF: Pages 62-64, section 5.3.\n"));
1058 if (ppd
->shortnickname
!= NULL
)
1060 if (strlen(ppd
->shortnickname
) > 31)
1064 if (!errors
&& !verbose
)
1065 _cupsLangPuts(stdout
, _(" FAIL\n"));
1067 _cupsLangPuts(stdout
,
1068 _(" **FAIL** BAD ShortNickName - longer "
1070 " REF: Pages 64-65, section 5.3.\n"));
1075 else if (verbose
> 0)
1076 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
1078 else if (ppdversion
>= 43)
1082 if (!errors
&& !verbose
)
1083 _cupsLangPuts(stdout
, _(" FAIL\n"));
1085 _cupsLangPuts(stdout
,
1086 _(" **FAIL** REQUIRED ShortNickName\n"
1087 " REF: Page 64-65, section 5.3.\n"));
1093 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
1094 strstr(ppd
->patches
, "*End"))
1098 if (!errors
&& !verbose
)
1099 _cupsLangPuts(stdout
, _(" FAIL\n"));
1101 _cupsLangPuts(stdout
,
1102 _(" **FAIL** BAD JobPatchFile attribute in file\n"
1103 " REF: Page 24, section 3.4.\n"));
1110 * Check for page sizes without the corresponding ImageableArea or
1111 * PaperDimension values...
1114 if (ppd
->num_sizes
== 0)
1118 if (!errors
&& !verbose
)
1119 _cupsLangPuts(stdout
, _(" FAIL\n"));
1121 _cupsLangPuts(stdout
,
1122 _(" **FAIL** REQUIRED PageSize\n"
1123 " REF: Page 41, section 5.\n"
1124 " REF: Page 99, section 5.14.\n"));
1131 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
1134 * Don't check custom size...
1137 if (!strcmp(size
->name
, "Custom"))
1141 * Check for ImageableArea...
1144 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
1145 size
->right
== 0.0 && size
->top
== 0.0)
1149 if (!errors
&& !verbose
)
1150 _cupsLangPuts(stdout
, _(" FAIL\n"));
1152 _cupsLangPrintf(stdout
,
1153 _(" **FAIL** REQUIRED ImageableArea for "
1155 " REF: Page 41, section 5.\n"
1156 " REF: Page 102, section 5.15.\n"),
1164 * Check for PaperDimension...
1167 if (size
->width
== 0.0 && size
->length
== 0.0)
1171 if (!errors
&& !verbose
)
1172 _cupsLangPuts(stdout
, _(" FAIL\n"));
1174 _cupsLangPrintf(stdout
,
1175 _(" **FAIL** REQUIRED PaperDimension "
1177 " REF: Page 41, section 5.\n"
1178 " REF: Page 103, section 5.15.\n"),
1188 * Check for valid Resolution, JCLResolution, or SetResolution values...
1191 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
1192 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
1193 option
= ppdFindOption(ppd
, "SetResolution");
1197 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
1200 * Verify that all resolution options are of the form NNNdpi
1204 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
1205 if (ptr
> choice
->choice
&& xdpi
> 0)
1208 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1215 if (xdpi
<= 0 || xdpi
> 99999 || ydpi
<= 0 || ydpi
> 99999 ||
1220 if (!errors
&& !verbose
)
1221 _cupsLangPuts(stdout
, _(" FAIL\n"));
1223 _cupsLangPrintf(stdout
,
1224 _(" **FAIL** Bad %s choice %s!\n"
1225 " REF: Page 84, section 5.9\n"),
1226 option
->keyword
, choice
->choice
);
1234 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1235 strcmp(attr
->name
, "1284DeviceID"))
1239 if (!errors
&& !verbose
)
1240 _cupsLangPuts(stdout
, _(" FAIL\n"));
1242 _cupsLangPrintf(stdout
,
1243 _(" **FAIL** %s must be 1284DeviceID!\n"
1244 " REF: Page 72, section 5.5\n"),
1251 errors
= check_case(ppd
, errors
, verbose
);
1253 if (!(warn
& WARN_CONSTRAINTS
))
1254 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1256 if (!(warn
& WARN_FILTERS
))
1257 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1259 if (!(warn
& WARN_PROFILES
))
1260 errors
= check_profiles(ppd
, root
, errors
, verbose
, 0);
1262 if (!(warn
& WARN_SIZES
))
1263 errors
= check_sizes(ppd
, errors
, verbose
, 0);
1265 if (!(warn
& WARN_TRANSLATIONS
))
1266 errors
= check_translations(ppd
, errors
, verbose
, 0);
1268 if (!(warn
& WARN_DUPLEX
))
1269 errors
= check_duplex(ppd
, errors
, verbose
, 0);
1271 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1275 * This file contains localizations, check for conformance of the
1276 * base translation...
1279 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1281 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1283 if (!errors
&& !verbose
)
1284 _cupsLangPuts(stdout
, _(" FAIL\n"));
1287 _cupsLangPrintf(stdout
,
1288 _(" **FAIL** Bad LanguageEncoding %s - "
1289 "must be ISOLatin1!\n"),
1290 attr
->value
? attr
->value
: "(null)");
1295 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1297 if (!errors
&& !verbose
)
1298 _cupsLangPuts(stdout
, _(" FAIL\n"));
1301 _cupsLangPrintf(stdout
,
1302 _(" **FAIL** Bad LanguageVersion %s - "
1303 "must be English!\n"),
1304 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1310 * Loop through all options and choices...
1313 for (option
= ppdFirstOption(ppd
);
1315 option
= ppdNextOption(ppd
))
1318 * Check for special characters outside A0 to BF, F7, or F8
1319 * that are used for languages other than English.
1322 for (ptr
= option
->text
; *ptr
; ptr
++)
1323 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1324 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1329 if (!errors
&& !verbose
)
1330 _cupsLangPuts(stdout
, _(" FAIL\n"));
1333 _cupsLangPrintf(stdout
,
1334 _(" **FAIL** Default translation "
1335 "string for option %s contains 8-bit "
1342 for (j
= 0; j
< option
->num_choices
; j
++)
1345 * Check for special characters outside A0 to BF, F7, or F8
1346 * that are used for languages other than English.
1349 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1350 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1351 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1356 if (!errors
&& !verbose
)
1357 _cupsLangPuts(stdout
, _(" FAIL\n"));
1360 _cupsLangPrintf(stdout
,
1361 _(" **FAIL** Default translation "
1362 "string for option %s choice %s contains "
1363 "8-bit characters!\n"),
1365 option
->choices
[j
].choice
);
1375 * Final pass/fail notification...
1379 status
= ERROR_CONFORMANCE
;
1381 _cupsLangPuts(stdout
, _(" PASS\n"));
1385 check_basics(argv
[i
]);
1387 if (warn
& WARN_CONSTRAINTS
)
1388 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1390 if (warn
& WARN_DEFAULTS
)
1391 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1393 if (warn
& WARN_PROFILES
)
1394 errors
= check_profiles(ppd
, root
, errors
, verbose
, 1);
1396 if (warn
& WARN_FILTERS
)
1397 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1399 if (warn
& WARN_SIZES
)
1400 errors
= check_sizes(ppd
, errors
, verbose
, 1);
1402 errors
= check_sizes(ppd
, errors
, verbose
, 2);
1404 if (warn
& WARN_TRANSLATIONS
)
1405 errors
= check_translations(ppd
, errors
, verbose
, 1);
1407 if (warn
& WARN_DUPLEX
)
1408 errors
= check_duplex(ppd
, errors
, verbose
, 1);
1411 * Look for legacy duplex keywords...
1414 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1415 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1416 option
= ppdFindOption(ppd
, "KD03Duplex");
1419 _cupsLangPrintf(stdout
,
1420 _(" WARN Duplex option keyword %s may not "
1421 "work as expected and should be named Duplex!\n"
1422 " REF: Page 122, section 5.17\n"),
1426 * Look for default keywords with no corresponding option...
1429 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1431 attr
= ppd
->attrs
[j
];
1433 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1434 !strcmp(attr
->name
, "DefaultColorSep") ||
1435 !strcmp(attr
->name
, "DefaultFont") ||
1436 !strcmp(attr
->name
, "DefaultHalftoneType") ||
1437 !strcmp(attr
->name
, "DefaultImageableArea") ||
1438 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
1439 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1440 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1441 !strcmp(attr
->name
, "DefaultResolution") ||
1442 !strcmp(attr
->name
, "DefaultScreenProc") ||
1443 !strcmp(attr
->name
, "DefaultTransfer"))
1446 if (!strncmp(attr
->name
, "Default", 7) &&
1447 !ppdFindOption(ppd
, attr
->name
+ 7))
1448 _cupsLangPrintf(stdout
,
1449 _(" WARN %s has no corresponding "
1454 ppdMarkDefaults(ppd
);
1455 if (ppdConflicts(ppd
))
1457 _cupsLangPuts(stdout
,
1458 _(" WARN Default choices conflicting!\n"));
1460 show_conflicts(ppd
);
1463 if (ppdversion
< 43)
1465 _cupsLangPrintf(stdout
,
1466 _(" WARN Obsolete PPD version %.1f!\n"
1467 " REF: Page 42, section 5.2.\n"),
1471 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1473 _cupsLangPuts(stdout
,
1474 _(" WARN LanguageEncoding required by PPD "
1476 " REF: Pages 56-57, section 5.3.\n"));
1479 if (!ppd
->manufacturer
&& ppdversion
< 43)
1481 _cupsLangPuts(stdout
,
1482 _(" WARN Manufacturer required by PPD "
1484 " REF: Pages 58-59, section 5.3.\n"));
1488 * Treat a PCFileName attribute longer than 12 characters as
1489 * a warning and not a hard error...
1492 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1494 _cupsLangPuts(stdout
,
1495 _(" WARN PCFileName longer than 8.3 in "
1496 "violation of PPD spec.\n"
1497 " REF: Pages 61-62, section 5.3.\n"));
1500 if (!ppd
->shortnickname
&& ppdversion
< 43)
1502 _cupsLangPuts(stdout
,
1503 _(" WARN ShortNickName required by PPD "
1505 " REF: Pages 64-65, section 5.3.\n"));
1509 * Check the Protocols line and flag PJL + BCP since TBCP is
1510 * usually used with PJL...
1515 if (strstr(ppd
->protocols
, "PJL") &&
1516 strstr(ppd
->protocols
, "BCP") &&
1517 !strstr(ppd
->protocols
, "TBCP"))
1519 _cupsLangPuts(stdout
,
1520 _(" WARN Protocols contains both PJL "
1521 "and BCP; expected TBCP.\n"
1522 " REF: Pages 78-79, section 5.7.\n"));
1525 if (strstr(ppd
->protocols
, "PJL") &&
1526 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1528 _cupsLangPuts(stdout
,
1529 _(" WARN Protocols contains PJL but JCL "
1530 "attributes are not set.\n"
1531 " REF: Pages 78-79, section 5.7.\n"));
1536 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1537 * which are errors according to the spec but won't cause problems
1538 * with CUPS specifically...
1541 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1542 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1544 len
= strlen(option
->keyword
);
1546 for (m
= 0, group2
= ppd
->groups
;
1547 m
< ppd
->num_groups
;
1549 for (n
= 0, option2
= group2
->options
;
1550 n
< group2
->num_options
;
1552 if (option
!= option2
&&
1553 len
< strlen(option2
->keyword
) &&
1554 !strncmp(option
->keyword
, option2
->keyword
, len
))
1556 _cupsLangPrintf(stdout
,
1557 _(" WARN %s shares a common "
1559 " REF: Page 15, section "
1561 option
->keyword
, option2
->keyword
);
1569 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1571 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1575 * Then list the options, if "-v" was provided...
1580 _cupsLangPrintf(stdout
,
1582 " language_level = %d\n"
1583 " color_device = %s\n"
1584 " variable_sizes = %s\n"
1585 " landscape = %d\n",
1586 ppd
->language_level
,
1587 ppd
->color_device
? "TRUE" : "FALSE",
1588 ppd
->variable_sizes
? "TRUE" : "FALSE",
1591 switch (ppd
->colorspace
)
1594 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1597 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1600 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1603 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1606 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1610 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1611 ppd
->num_emulations
);
1612 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1613 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1614 j
, ppd
->emulations
[j
].name
);
1616 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1617 ppd
->lang_encoding
);
1618 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1620 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1621 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1622 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1623 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1625 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1626 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1627 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1628 ppd
->shortnickname
);
1629 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1630 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1632 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1633 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1635 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1638 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1640 _cupsLangPrintf(stdout
,
1641 " options[%d] = %s (%s) %s %s %.0f "
1643 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1644 sections
[option
->section
], option
->order
,
1645 option
->num_choices
);
1647 if (!strcmp(option
->keyword
, "PageSize") ||
1648 !strcmp(option
->keyword
, "PageRegion"))
1650 for (m
= option
->num_choices
, choice
= option
->choices
;
1654 size
= ppdPageSize(ppd
, choice
->choice
);
1657 _cupsLangPrintf(stdout
,
1659 choice
->choice
, choice
->text
);
1661 _cupsLangPrintf(stdout
,
1662 " %s (%s) = %.2fx%.2fin "
1663 "(%.1f,%.1f,%.1f,%.1f)",
1664 choice
->choice
, choice
->text
,
1665 size
->width
/ 72.0, size
->length
/ 72.0,
1666 size
->left
/ 72.0, size
->bottom
/ 72.0,
1667 size
->right
/ 72.0, size
->top
/ 72.0);
1669 if (!strcmp(option
->defchoice
, choice
->choice
))
1670 _cupsLangPuts(stdout
, " *\n");
1672 _cupsLangPuts(stdout
, "\n");
1677 for (m
= option
->num_choices
, choice
= option
->choices
;
1681 _cupsLangPrintf(stdout
, " %s (%s)",
1682 choice
->choice
, choice
->text
);
1684 if (!strcmp(option
->defchoice
, choice
->choice
))
1685 _cupsLangPuts(stdout
, " *\n");
1687 _cupsLangPuts(stdout
, "\n");
1693 _cupsLangPrintf(stdout
, " num_consts = %d\n",
1695 for (j
= 0; j
< ppd
->num_consts
; j
++)
1696 _cupsLangPrintf(stdout
,
1697 " consts[%d] = *%s %s *%s %s\n",
1698 j
, ppd
->consts
[j
].option1
, ppd
->consts
[j
].choice1
,
1699 ppd
->consts
[j
].option2
, ppd
->consts
[j
].choice2
);
1701 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1703 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1704 _cupsLangPrintf(stdout
,
1705 " profiles[%d] = %s/%s %.3f %.3f "
1706 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1707 j
, ppd
->profiles
[j
].resolution
,
1708 ppd
->profiles
[j
].media_type
,
1709 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1710 ppd
->profiles
[j
].matrix
[0][0],
1711 ppd
->profiles
[j
].matrix
[0][1],
1712 ppd
->profiles
[j
].matrix
[0][2],
1713 ppd
->profiles
[j
].matrix
[1][0],
1714 ppd
->profiles
[j
].matrix
[1][1],
1715 ppd
->profiles
[j
].matrix
[1][2],
1716 ppd
->profiles
[j
].matrix
[2][0],
1717 ppd
->profiles
[j
].matrix
[2][1],
1718 ppd
->profiles
[j
].matrix
[2][2]);
1720 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1721 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1722 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1725 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1726 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1727 _cupsLangPrintf(stdout
,
1728 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1729 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1730 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1731 ppd
->attrs
[j
]->text
,
1732 ppd
->attrs
[j
]->value
?
1733 ppd
->attrs
[j
]->value
: "(null)");
1747 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1751 check_basics(const char *filename
) /* I - PPD file to check */
1753 cups_file_t
*fp
; /* File pointer */
1754 int ch
; /* Current character */
1755 int col
, /* Current column */
1756 whitespace
; /* Only seen whitespace? */
1757 int eol
; /* Line endings */
1758 int linenum
; /* Line number */
1759 int mixed
; /* Mixed line endings? */
1762 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1771 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1773 if (ch
== '\r' || ch
== '\n')
1777 if (eol
== EOL_NONE
)
1779 else if (eol
!= EOL_LF
)
1782 else if (ch
== '\r')
1784 if (cupsFilePeekChar(fp
) == '\n')
1786 cupsFileGetChar(fp
);
1788 if (eol
== EOL_NONE
)
1790 else if (eol
!= EOL_CRLF
)
1793 else if (eol
== EOL_NONE
)
1795 else if (eol
!= EOL_CR
)
1799 if (col
> 0 && whitespace
)
1800 _cupsLangPrintf(stdout
,
1801 _(" WARN Line %d only contains whitespace!\n"),
1810 if (ch
!= ' ' && ch
!= '\t')
1818 _cupsLangPuts(stdout
,
1819 _(" WARN File contains a mix of CR, LF, and "
1820 "CR LF line endings!\n"));
1822 if (eol
== EOL_CRLF
)
1823 _cupsLangPuts(stdout
,
1824 _(" WARN Non-Windows PPD files should use lines "
1825 "ending with only LF, not CR LF!\n"));
1832 * 'check_constraints()' - Check UIConstraints in the PPD file.
1835 static int /* O - Errors found */
1836 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1837 int errors
, /* I - Errors found */
1838 int verbose
, /* I - Verbosity level */
1839 int warn
) /* I - Warnings only? */
1841 int i
; /* Looping var */
1842 const char *prefix
; /* WARN/FAIL prefix */
1843 ppd_const_t
*c
; /* Current UIConstraints data */
1844 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
1845 const char *vptr
; /* Pointer into constraint value */
1846 char option
[PPD_MAX_NAME
],
1847 /* Option name/MainKeyword */
1848 choice
[PPD_MAX_NAME
],
1849 /* Choice/OptionKeyword */
1850 *ptr
; /* Pointer into option or choice */
1851 int num_options
; /* Number of options */
1852 cups_option_t
*options
; /* Options */
1853 ppd_option_t
*o
; /* PPD option */
1856 prefix
= warn
? " WARN " : "**FAIL**";
1860 * See what kind of constraint data we have in the PPD...
1863 if ((constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
)) != NULL
)
1866 * Check new-style cupsUIConstraints data...
1870 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
1872 if (!constattr
->value
)
1874 if (!warn
&& !errors
&& !verbose
)
1875 _cupsLangPuts(stdout
, _(" FAIL\n"));
1877 _cupsLangPrintf(stdout
,
1878 _(" %s Empty cupsUIConstraints %s!\n"),
1879 prefix
, constattr
->spec
);
1887 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
1889 i
++, vptr
= strchr(vptr
+ 1, '*'));
1893 if (!warn
&& !errors
&& !verbose
)
1894 _cupsLangPuts(stdout
, _(" FAIL\n"));
1896 _cupsLangPrintf(stdout
,
1897 _(" %s Bad cupsUIConstraints %s: \"%s\"!\n"),
1898 prefix
, constattr
->spec
, constattr
->value
);
1906 cupsArraySave(ppd
->sorted_attrs
);
1908 if (constattr
->spec
[0] &&
1909 !ppdFindAttr(ppd
, "cupsUIResolver", constattr
->spec
))
1911 if (!warn
&& !errors
&& !verbose
)
1912 _cupsLangPuts(stdout
, _(" FAIL\n"));
1914 _cupsLangPrintf(stdout
,
1915 _(" %s Missing cupsUIResolver %s!\n"),
1916 prefix
, constattr
->spec
);
1922 cupsArrayRestore(ppd
->sorted_attrs
);
1927 for (vptr
= strchr(constattr
->value
, '*');
1929 vptr
= strchr(vptr
, '*'))
1932 * Extract "*Option Choice" or just "*Option"...
1935 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1936 if (ptr
< (option
+ sizeof(option
) - 1))
1941 while (isspace(*vptr
& 255))
1948 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
1949 if (ptr
< (choice
+ sizeof(choice
) - 1))
1955 if (!strncasecmp(option
, "Custom", 6) && !strcasecmp(choice
, "True"))
1957 _cups_strcpy(option
, option
+ 6);
1958 strcpy(choice
, "Custom");
1961 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
1963 if (!warn
&& !errors
&& !verbose
)
1964 _cupsLangPuts(stdout
, _(" FAIL\n"));
1966 _cupsLangPrintf(stdout
,
1967 _(" %s Missing option %s in "
1968 "cupsUIConstraints %s: \"%s\"!\n"),
1969 prefix
, option
, constattr
->spec
, constattr
->value
);
1977 if (choice
[0] && !ppdFindChoice(o
, choice
))
1979 if (!warn
&& !errors
&& !verbose
)
1980 _cupsLangPuts(stdout
, _(" FAIL\n"));
1982 _cupsLangPrintf(stdout
,
1983 _(" %s Missing choice *%s %s in "
1984 "cupsUIConstraints %s: \"%s\"!\n"),
1985 prefix
, option
, choice
, constattr
->spec
,
1995 num_options
= cupsAddOption(option
, choice
, num_options
, &options
);
1998 for (i
= 0; i
< o
->num_choices
; i
++)
1999 if (strcasecmp(o
->choices
[i
].choice
, "None") &&
2000 strcasecmp(o
->choices
[i
].choice
, "Off") &&
2001 strcasecmp(o
->choices
[i
].choice
, "False"))
2003 num_options
= cupsAddOption(option
, o
->choices
[i
].choice
,
2004 num_options
, &options
);
2011 * Resolvers must list at least two options...
2014 if (num_options
< 2)
2016 if (!warn
&& !errors
&& !verbose
)
2017 _cupsLangPuts(stdout
, _(" FAIL\n"));
2019 _cupsLangPrintf(stdout
,
2020 _(" %s cupsUIResolver %s does not list at least "
2021 "two different options!\n"),
2022 prefix
, constattr
->spec
);
2029 * Test the resolver...
2032 if (!cupsResolveConflicts(ppd
, NULL
, NULL
, &num_options
, &options
))
2034 if (!warn
&& !errors
&& !verbose
)
2035 _cupsLangPuts(stdout
, _(" FAIL\n"));
2037 _cupsLangPrintf(stdout
,
2038 _(" %s cupsUIResolver %s causes a loop!\n"),
2039 prefix
, constattr
->spec
);
2045 cupsFreeOptions(num_options
, options
);
2051 * Check old-style [Non]UIConstraints data...
2054 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
2056 if (!strncasecmp(c
->option1
, "Custom", 6) &&
2057 !strcasecmp(c
->choice1
, "True"))
2059 strcpy(option
, c
->option1
+ 6);
2060 strcpy(choice
, "Custom");
2064 strcpy(option
, c
->option1
);
2065 strcpy(choice
, c
->choice1
);
2068 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
2070 if (!warn
&& !errors
&& !verbose
)
2071 _cupsLangPuts(stdout
, _(" FAIL\n"));
2073 _cupsLangPrintf(stdout
,
2074 _(" %s Missing option %s in "
2075 "UIConstraints \"*%s %s *%s %s\"!\n"),
2077 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2082 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2084 if (!warn
&& !errors
&& !verbose
)
2085 _cupsLangPuts(stdout
, _(" FAIL\n"));
2087 _cupsLangPrintf(stdout
,
2088 _(" %s Missing choice *%s %s in "
2089 "UIConstraints \"*%s %s *%s %s\"!\n"),
2090 prefix
, c
->option1
, c
->choice1
,
2091 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2097 if (!strncasecmp(c
->option2
, "Custom", 6) &&
2098 !strcasecmp(c
->choice2
, "True"))
2100 strcpy(option
, c
->option2
+ 6);
2101 strcpy(choice
, "Custom");
2105 strcpy(option
, c
->option2
);
2106 strcpy(choice
, c
->choice2
);
2109 if ((o
= ppdFindOption(ppd
, option
)) == NULL
)
2111 if (!warn
&& !errors
&& !verbose
)
2112 _cupsLangPuts(stdout
, _(" FAIL\n"));
2114 _cupsLangPrintf(stdout
,
2115 _(" %s Missing option %s in "
2116 "UIConstraints \"*%s %s *%s %s\"!\n"),
2118 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2123 else if (choice
[0] && !ppdFindChoice(o
, choice
))
2125 if (!warn
&& !errors
&& !verbose
)
2126 _cupsLangPuts(stdout
, _(" FAIL\n"));
2128 _cupsLangPrintf(stdout
,
2129 _(" %s Missing choice *%s %s in "
2130 "UIConstraints \"*%s %s *%s %s\"!\n"),
2131 prefix
, c
->option2
, c
->choice2
,
2132 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2145 * 'check_case()' - Check that there are no duplicate groups, options,
2146 * or choices that differ only by case.
2149 static int /* O - Errors found */
2150 check_case(ppd_file_t
*ppd
, /* I - PPD file */
2151 int errors
, /* I - Errors found */
2152 int verbose
) /* I - Verbosity level */
2154 int i
, j
; /* Looping vars */
2155 ppd_group_t
*groupa
, /* First group */
2156 *groupb
; /* Second group */
2157 ppd_option_t
*optiona
, /* First option */
2158 *optionb
; /* Second option */
2159 ppd_choice_t
*choicea
, /* First choice */
2160 *choiceb
; /* Second choice */
2164 * Check that the groups do not have any duplicate names...
2167 for (i
= ppd
->num_groups
, groupa
= ppd
->groups
; i
> 1; i
--, groupa
++)
2168 for (j
= i
- 1, groupb
= groupa
+ 1; j
> 0; j
--, groupb
++)
2169 if (!strcasecmp(groupa
->name
, groupb
->name
))
2171 if (!errors
&& !verbose
)
2172 _cupsLangPuts(stdout
, _(" FAIL\n"));
2175 _cupsLangPrintf(stdout
,
2176 _(" **FAIL** Group names %s and %s differ only "
2178 groupa
->name
, groupb
->name
);
2184 * Check that the options do not have any duplicate names...
2187 for (optiona
= ppdFirstOption(ppd
); optiona
; optiona
= ppdNextOption(ppd
))
2189 cupsArraySave(ppd
->options
);
2190 for (optionb
= ppdNextOption(ppd
); optionb
; optionb
= ppdNextOption(ppd
))
2191 if (!strcasecmp(optiona
->keyword
, optionb
->keyword
))
2193 if (!errors
&& !verbose
)
2194 _cupsLangPuts(stdout
, _(" FAIL\n"));
2197 _cupsLangPrintf(stdout
,
2198 _(" **FAIL** Option names %s and %s differ only "
2200 optiona
->keyword
, optionb
->keyword
);
2204 cupsArrayRestore(ppd
->options
);
2207 * Then the choices...
2210 for (i
= optiona
->num_choices
, choicea
= optiona
->choices
;
2213 for (j
= i
- 1, choiceb
= choicea
+ 1; j
> 0; j
--, choiceb
++)
2214 if (!strcmp(choicea
->choice
, choiceb
->choice
))
2216 if (!errors
&& !verbose
)
2217 _cupsLangPuts(stdout
, _(" FAIL\n"));
2220 _cupsLangPrintf(stdout
,
2221 _(" **FAIL** Multiple occurrences of %s "
2222 "choice name %s!\n"),
2223 optiona
->keyword
, choicea
->choice
);
2231 else if (!strcasecmp(choicea
->choice
, choiceb
->choice
))
2233 if (!errors
&& !verbose
)
2234 _cupsLangPuts(stdout
, _(" FAIL\n"));
2237 _cupsLangPrintf(stdout
,
2238 _(" **FAIL** %s choice names %s and %s "
2239 "differ only by case!\n"),
2240 optiona
->keyword
, choicea
->choice
, choiceb
->choice
);
2247 * Return the number of errors found...
2255 * 'check_defaults()' - Check default option keywords in the PPD file.
2258 static int /* O - Errors found */
2259 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
2260 int errors
, /* I - Errors found */
2261 int verbose
, /* I - Verbosity level */
2262 int warn
) /* I - Warnings only? */
2264 int j
, k
; /* Looping vars */
2265 ppd_attr_t
*attr
; /* PPD attribute */
2266 ppd_option_t
*option
; /* Standard UI option */
2267 const char *prefix
; /* WARN/FAIL prefix */
2270 prefix
= warn
? " WARN " : "**FAIL**";
2272 for (j
= 0; j
< ppd
->num_attrs
; j
++)
2274 attr
= ppd
->attrs
[j
];
2276 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
2277 !strcmp(attr
->name
, "DefaultFont") ||
2278 !strcmp(attr
->name
, "DefaultHalftoneType") ||
2279 !strcmp(attr
->name
, "DefaultImageableArea") ||
2280 !strcmp(attr
->name
, "DefaultLeadingEdge") ||
2281 !strcmp(attr
->name
, "DefaultOutputOrder") ||
2282 !strcmp(attr
->name
, "DefaultPaperDimension") ||
2283 !strcmp(attr
->name
, "DefaultResolution") ||
2284 !strcmp(attr
->name
, "DefaultTransfer"))
2287 if (!strncmp(attr
->name
, "Default", 7))
2289 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
2290 strcmp(attr
->value
, "Unknown"))
2293 * Check that the default option value matches a choice...
2296 for (k
= 0; k
< option
->num_choices
; k
++)
2297 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
2300 if (k
>= option
->num_choices
)
2302 if (!warn
&& !errors
&& !verbose
)
2303 _cupsLangPuts(stdout
, _(" FAIL\n"));
2306 _cupsLangPrintf(stdout
,
2307 _(" %s %s %s does not exist!\n"),
2308 prefix
, attr
->name
, attr
->value
);
2322 * 'check_duplex()' - Check duplex keywords in the PPD file.
2325 static int /* O - Errors found */
2326 check_duplex(ppd_file_t
*ppd
, /* I - PPD file */
2327 int errors
, /* I - Error found */
2328 int verbose
, /* I - Verbosity level */
2329 int warn
) /* I - Warnings only? */
2331 int i
; /* Looping var */
2332 ppd_option_t
*option
; /* PPD option */
2333 ppd_choice_t
*choice
; /* Current choice */
2334 const char *prefix
; /* Message prefix */
2337 prefix
= warn
? " WARN " : "**FAIL**";
2340 * Check for a duplex option, and for standard values...
2343 if ((option
= ppdFindOption(ppd
, "Duplex")) != NULL
)
2345 if (!ppdFindChoice(option
, "None"))
2349 if (!warn
&& !errors
&& !verbose
)
2350 _cupsLangPuts(stdout
, _(" FAIL\n"));
2352 _cupsLangPrintf(stdout
,
2353 _(" %s REQUIRED %s does not define "
2355 " REF: Page 122, section 5.17\n"),
2356 prefix
, option
->keyword
);
2363 for (i
= option
->num_choices
, choice
= option
->choices
;
2366 if (strcmp(choice
->choice
, "None") &&
2367 strcmp(choice
->choice
, "DuplexNoTumble") &&
2368 strcmp(choice
->choice
, "DuplexTumble") &&
2369 strcmp(choice
->choice
, "SimplexTumble"))
2373 if (!warn
&& !errors
&& !verbose
)
2374 _cupsLangPuts(stdout
, _(" FAIL\n"));
2376 _cupsLangPrintf(stdout
,
2377 _(" %s Bad %s choice %s!\n"
2378 " REF: Page 122, section 5.17\n"),
2379 prefix
, option
->keyword
, choice
->choice
);
2392 * 'check_filters()' - Check filters in the PPD file.
2395 static int /* O - Errors found */
2396 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
2397 const char *root
, /* I - Root directory */
2398 int errors
, /* I - Errors found */
2399 int verbose
, /* I - Verbosity level */
2400 int warn
) /* I - Warnings only? */
2402 int i
; /* Looping var */
2403 ppd_attr_t
*attr
; /* PPD attribute */
2404 const char *ptr
; /* Pointer into string */
2405 char super
[16], /* Super-type for filter */
2406 type
[256], /* Type for filter */
2407 program
[1024], /* Program/filter name */
2408 pathprog
[1024]; /* Complete path to program/filter */
2409 int cost
; /* Cost of filter */
2410 const char *prefix
; /* WARN/FAIL prefix */
2413 prefix
= warn
? " WARN " : "**FAIL**";
2419 for (i
= 0; i
< ppd
->num_filters
; i
++)
2421 if (sscanf(ppd
->filters
[i
], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2422 &cost
, program
) != 4)
2424 if (!warn
&& !errors
&& !verbose
)
2425 _cupsLangPuts(stdout
, _(" FAIL\n"));
2428 _cupsLangPrintf(stdout
,
2429 _(" %s Bad cupsFilter value \"%s\"!\n"),
2430 prefix
, ppd
->filters
[i
]);
2435 else if (strcmp(program
, "-"))
2437 if (program
[0] == '/')
2438 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2441 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2442 ptr
= CUPS_SERVERBIN
;
2444 if (*ptr
== '/' || !*root
)
2445 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2448 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2452 if (access(pathprog
, X_OK
))
2454 if (!warn
&& !errors
&& !verbose
)
2455 _cupsLangPuts(stdout
, _(" FAIL\n"));
2458 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
2459 "file \"%s\"\n"), prefix
, program
);
2465 errors
= valid_path("cupsFilter", pathprog
, errors
, verbose
, warn
);
2473 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
2475 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
2477 if (strcmp(attr
->name
, "cupsPreFilter"))
2479 if (!warn
&& !errors
&& !verbose
)
2480 _cupsLangPuts(stdout
, _(" FAIL\n"));
2483 _cupsLangPrintf(stdout
,
2484 _(" %s Bad spelling of %s - should be %s!\n"),
2485 prefix
, attr
->name
, "cupsPreFilter");
2492 sscanf(attr
->value
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
,
2493 &cost
, program
) != 4)
2495 if (!warn
&& !errors
&& !verbose
)
2496 _cupsLangPuts(stdout
, _(" FAIL\n"));
2499 _cupsLangPrintf(stdout
,
2500 _(" %s Bad cupsPreFilter value \"%s\"!\n"),
2501 prefix
, attr
->value
? attr
->value
: "");
2506 else if (strcmp(program
, "-"))
2508 if (program
[0] == '/')
2509 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
2512 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
2513 ptr
= CUPS_SERVERBIN
;
2515 if (*ptr
== '/' || !*root
)
2516 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
2519 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
2523 if (access(pathprog
, X_OK
))
2525 if (!warn
&& !errors
&& !verbose
)
2526 _cupsLangPuts(stdout
, _(" FAIL\n"));
2529 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
2530 "file \"%s\"\n"), prefix
, program
);
2536 errors
= valid_path("cupsPreFilter", pathprog
, errors
, verbose
, warn
);
2545 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
2547 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
2549 if (strcmp(attr
->name
, "APDialogExtension"))
2551 if (!warn
&& !errors
&& !verbose
)
2552 _cupsLangPuts(stdout
, _(" FAIL\n"));
2555 _cupsLangPrintf(stdout
,
2556 _(" %s Bad spelling of %s - should be %s!\n"),
2557 prefix
, attr
->name
, "APDialogExtension");
2563 if (!attr
->value
|| access(attr
->value
, 0))
2565 if (!warn
&& !errors
&& !verbose
)
2566 _cupsLangPuts(stdout
, _(" FAIL\n"));
2569 _cupsLangPrintf(stdout
, _(" %s Missing "
2570 "APDialogExtension file \"%s\"\n"),
2571 prefix
, attr
->value
? attr
->value
: "<NULL>");
2577 errors
= valid_path("APDialogExtension", attr
->value
, errors
, verbose
,
2585 if ((attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
)) != NULL
)
2587 if (strcmp(attr
->name
, "APPrinterIconPath"))
2589 if (!warn
&& !errors
&& !verbose
)
2590 _cupsLangPuts(stdout
, _(" FAIL\n"));
2593 _cupsLangPrintf(stdout
,
2594 _(" %s Bad spelling of %s - should be %s!\n"),
2595 prefix
, attr
->name
, "APPrinterIconPath");
2601 if (!attr
->value
|| access(attr
->value
, 0))
2603 if (!warn
&& !errors
&& !verbose
)
2604 _cupsLangPuts(stdout
, _(" FAIL\n"));
2607 _cupsLangPrintf(stdout
, _(" %s Missing "
2608 "APPrinterIconPath file \"%s\"\n"),
2609 prefix
, attr
->value
? attr
->value
: "<NULL>");
2615 errors
= valid_path("APPrinterIconPath", attr
->value
, errors
, verbose
,
2620 * APPrinterLowInkTool
2623 if ((attr
= ppdFindAttr(ppd
, "APPrinterLowInkTool", NULL
)) != NULL
)
2625 if (strcmp(attr
->name
, "APPrinterLowInkTool"))
2627 if (!warn
&& !errors
&& !verbose
)
2628 _cupsLangPuts(stdout
, _(" FAIL\n"));
2631 _cupsLangPrintf(stdout
,
2632 _(" %s Bad spelling of %s - should be %s!\n"),
2633 prefix
, attr
->name
, "APPrinterLowInkTool");
2639 if (!attr
->value
|| access(attr
->value
, 0))
2641 if (!warn
&& !errors
&& !verbose
)
2642 _cupsLangPuts(stdout
, _(" FAIL\n"));
2645 _cupsLangPrintf(stdout
, _(" %s Missing "
2646 "APPrinterLowInkTool file \"%s\"\n"),
2647 prefix
, attr
->value
? attr
->value
: "<NULL>");
2653 errors
= valid_path("APPrinterLowInkTool", attr
->value
, errors
, verbose
,
2658 * APPrinterUtilityPath
2661 if ((attr
= ppdFindAttr(ppd
, "APPrinterUtilityPath", NULL
)) != NULL
)
2663 if (strcmp(attr
->name
, "APPrinterUtilityPath"))
2665 if (!warn
&& !errors
&& !verbose
)
2666 _cupsLangPuts(stdout
, _(" FAIL\n"));
2669 _cupsLangPrintf(stdout
,
2670 _(" %s Bad spelling of %s - should be %s!\n"),
2671 prefix
, attr
->name
, "APPrinterUtilityPath");
2677 if (!attr
->value
|| access(attr
->value
, 0))
2679 if (!warn
&& !errors
&& !verbose
)
2680 _cupsLangPuts(stdout
, _(" FAIL\n"));
2683 _cupsLangPrintf(stdout
, _(" %s Missing "
2684 "APPrinterUtilityPath file \"%s\"\n"),
2685 prefix
, attr
->value
? attr
->value
: "<NULL>");
2691 errors
= valid_path("APPrinterUtilityPath", attr
->value
, errors
, verbose
,
2696 * APScanAppBundleID and APScanAppPath
2699 if ((attr
= ppdFindAttr(ppd
, "APScanAppPath", NULL
)) != NULL
)
2701 if (strcmp(attr
->name
, "APScanAppPath"))
2703 if (!warn
&& !errors
&& !verbose
)
2704 _cupsLangPuts(stdout
, _(" FAIL\n"));
2707 _cupsLangPrintf(stdout
,
2708 _(" %s Bad spelling of %s - should be %s!\n"),
2709 prefix
, attr
->name
, "APScanAppPath");
2715 if (!attr
->value
|| access(attr
->value
, 0))
2717 if (!warn
&& !errors
&& !verbose
)
2718 _cupsLangPuts(stdout
, _(" FAIL\n"));
2721 _cupsLangPrintf(stdout
, _(" %s Missing "
2722 "APScanAppPath file \"%s\"\n"),
2723 prefix
, attr
->value
? attr
->value
: "<NULL>");
2729 errors
= valid_path("APScanAppPath", attr
->value
, errors
, verbose
,
2732 if (ppdFindAttr(ppd
, "APScanAppBundleID", NULL
))
2734 if (!warn
&& !errors
&& !verbose
)
2735 _cupsLangPuts(stdout
, _(" FAIL\n"));
2738 _cupsLangPrintf(stdout
, _(" %s Cannot provide both "
2739 "APScanAppPath and APScanAppBundleID!\n"),
2746 #endif /* __APPLE__ */
2753 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2756 static int /* O - Errors found */
2757 check_profiles(ppd_file_t
*ppd
, /* I - PPD file */
2758 const char *root
, /* I - Root directory */
2759 int errors
, /* I - Errors found */
2760 int verbose
, /* I - Verbosity level */
2761 int warn
) /* I - Warnings only? */
2763 int i
; /* Looping var */
2764 ppd_attr_t
*attr
; /* PPD attribute */
2765 const char *ptr
; /* Pointer into string */
2766 const char *prefix
; /* WARN/FAIL prefix */
2767 char filename
[1024]; /* Profile filename */
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 (access(filename
, 0))
2824 if (!warn
&& !errors
&& !verbose
)
2825 _cupsLangPuts(stdout
, _(" FAIL\n"));
2828 _cupsLangPrintf(stdout
, _(" %s Missing cupsICCProfile "
2829 "file \"%s\"!\n"), prefix
, attr
->value
);
2835 errors
= valid_path("cupsICCProfile", filename
, errors
, verbose
, warn
);
2838 * Check for hash collisions...
2841 hash
= _ppdHashName(attr
->spec
);
2843 if (num_profiles
> 0)
2845 for (i
= 0; i
< num_profiles
; i
++)
2846 if (hashes
[i
] == hash
)
2849 if (i
< num_profiles
)
2851 if (!warn
&& !errors
&& !verbose
)
2852 _cupsLangPuts(stdout
, _(" FAIL\n"));
2855 _cupsLangPrintf(stdout
,
2856 _(" %s cupsICCProfile %s hash value "
2857 "collides with %s!\n"), prefix
, attr
->spec
,
2866 * Remember up to 1000 profiles...
2869 if (num_profiles
< 1000)
2871 hashes
[num_profiles
] = hash
;
2872 specs
[num_profiles
] = attr
->spec
;
2882 * 'check_sizes()' - Check media sizes in the PPD file.
2885 static int /* O - Errors found */
2886 check_sizes(ppd_file_t
*ppd
, /* I - PPD file */
2887 int errors
, /* I - Errors found */
2888 int verbose
, /* I - Verbosity level */
2889 int warn
) /* I - Warnings only? */
2891 int i
; /* Looping vars */
2892 ppd_size_t
*size
; /* Current size */
2893 int width
, /* Custom width */
2894 length
; /* Custom length */
2895 char name
[PPD_MAX_NAME
], /* Size name without dot suffix */
2896 *nameptr
; /* Pointer into name */
2897 const char *prefix
; /* WARN/FAIL prefix */
2898 ppd_option_t
*page_size
, /* PageSize option */
2899 *page_region
; /* PageRegion option */
2902 prefix
= warn
? " WARN " : "**FAIL**";
2904 if ((page_size
= ppdFindOption(ppd
, "PageSize")) == NULL
&& warn
!= 2)
2906 if (!warn
&& !errors
&& !verbose
)
2907 _cupsLangPuts(stdout
, _(" FAIL\n"));
2910 _cupsLangPrintf(stdout
,
2911 _(" %s Missing REQUIRED PageSize option!\n"
2912 " REF: Page 99, section 5.14.\n"),
2919 if ((page_region
= ppdFindOption(ppd
, "PageRegion")) == NULL
&& warn
!= 2)
2921 if (!warn
&& !errors
&& !verbose
)
2922 _cupsLangPuts(stdout
, _(" FAIL\n"));
2925 _cupsLangPrintf(stdout
,
2926 _(" %s Missing REQUIRED PageRegion option!\n"
2927 " REF: Page 100, section 5.14.\n"),
2934 for (i
= ppd
->num_sizes
, size
= ppd
->sizes
; i
> 0; i
--, size
++)
2937 * Check that the size name is standard...
2940 if (!strcmp(size
->name
, "Custom"))
2943 * Skip custom page size...
2948 else if (warn
!= 2 && size
->name
[0] == 'w' &&
2949 sscanf(size
->name
, "w%dh%d", &width
, &length
) == 2)
2952 * Validate device-specific size wNNNhNNN should have proper width and
2956 if (fabs(width
- size
->width
) >= 1.0 ||
2957 fabs(length
- size
->length
) >= 1.0)
2959 if (!warn
&& !errors
&& !verbose
)
2960 _cupsLangPuts(stdout
, _(" FAIL\n"));
2963 _cupsLangPrintf(stdout
,
2964 _(" %s Size \"%s\" has unexpected dimensions "
2966 prefix
, size
->name
, size
->width
, size
->length
);
2972 else if (warn
&& verbose
>= 0)
2975 * Lookup the size name in the standard size table...
2978 strlcpy(name
, size
->name
, sizeof(name
));
2979 if ((nameptr
= strchr(name
, '.')) != NULL
)
2982 if (!bsearch(name
, adobe_size_names
,
2983 sizeof(adobe_size_names
) /
2984 sizeof(adobe_size_names
[0]),
2985 sizeof(adobe_size_names
[0]),
2986 (int (*)(const void *, const void *))strcmp
))
2988 _cupsLangPrintf(stdout
,
2989 _(" %s Non-standard size name \"%s\"!\n"
2990 " REF: Page 187, section B.2.\n"),
2991 prefix
, size
->name
);
2996 * Verify that the size is defined for both PageSize and PageRegion...
2999 if (warn
!= 2 && !ppdFindChoice(page_size
, size
->name
))
3001 if (!warn
&& !errors
&& !verbose
)
3002 _cupsLangPuts(stdout
, _(" FAIL\n"));
3005 _cupsLangPrintf(stdout
,
3006 _(" %s Size \"%s\" defined for %s but not for "
3008 prefix
, size
->name
, "PageRegion", "PageSize");
3013 else if (warn
!= 2 && !ppdFindChoice(page_region
, size
->name
))
3015 if (!warn
&& !errors
&& !verbose
)
3016 _cupsLangPuts(stdout
, _(" FAIL\n"));
3019 _cupsLangPrintf(stdout
,
3020 _(" %s Size \"%s\" defined for %s but not for "
3022 prefix
, size
->name
, "PageSize", "PageRegion");
3034 * 'check_translations()' - Check translations in the PPD file.
3037 static int /* O - Errors found */
3038 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
3039 int errors
, /* I - Errors found */
3040 int verbose
, /* I - Verbosity level */
3041 int warn
) /* I - Warnings only? */
3043 int j
; /* Looping var */
3044 ppd_attr_t
*attr
; /* PPD attribute */
3045 cups_array_t
*languages
; /* Array of languages */
3046 int langlen
; /* Length of language */
3047 char *language
, /* Current language */
3048 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
3049 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
3050 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
3051 cllkeyword
[PPD_MAX_NAME
];
3052 /* Custom option keyword (base) */
3053 ppd_option_t
*option
; /* Standard UI option */
3054 ppd_coption_t
*coption
; /* Custom option */
3055 ppd_cparam_t
*cparam
; /* Custom parameter */
3056 char ll
[3]; /* Base language */
3057 const char *prefix
; /* WARN/FAIL prefix */
3058 const char *text
; /* Pointer into UI text */
3061 prefix
= warn
? " WARN " : "**FAIL**";
3063 if ((languages
= _ppdGetLanguages(ppd
)) != NULL
)
3066 * This file contains localizations, check them...
3069 for (language
= (char *)cupsArrayFirst(languages
);
3071 language
= (char *)cupsArrayNext(languages
))
3073 langlen
= strlen(language
);
3074 if (langlen
!= 2 && langlen
!= 5)
3076 if (!warn
&& !errors
&& !verbose
)
3077 _cupsLangPuts(stdout
, _(" FAIL\n"));
3080 _cupsLangPrintf(stdout
,
3081 _(" %s Bad language \"%s\"!\n"),
3090 if (!strcmp(language
, "en"))
3093 strlcpy(ll
, language
, sizeof(ll
));
3096 * Loop through all options and choices...
3099 for (option
= ppdFirstOption(ppd
);
3101 option
= ppdNextOption(ppd
))
3103 if (!strcmp(option
->keyword
, "PageRegion"))
3106 snprintf(keyword
, sizeof(keyword
), "%s.Translation", language
);
3107 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
3109 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
3110 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
3112 if (!warn
&& !errors
&& !verbose
)
3113 _cupsLangPuts(stdout
, _(" FAIL\n"));
3116 _cupsLangPrintf(stdout
,
3117 _(" %s Missing \"%s\" translation "
3118 "string for option %s!\n"),
3119 prefix
, language
, option
->keyword
);
3124 else if (!valid_utf8(attr
->text
))
3126 if (!warn
&& !errors
&& !verbose
)
3127 _cupsLangPuts(stdout
, _(" FAIL\n"));
3130 _cupsLangPrintf(stdout
,
3131 _(" %s Bad UTF-8 \"%s\" translation "
3132 "string for option %s!\n"),
3133 prefix
, language
, option
->keyword
);
3139 snprintf(keyword
, sizeof(keyword
), "%s.%s", language
,
3141 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
3144 for (j
= 0; j
< option
->num_choices
; j
++)
3147 * First see if this choice is a number; if so, don't require
3151 for (text
= option
->choices
[j
].text
; *text
; text
++)
3152 if (!strchr("0123456789-+.", *text
))
3159 * Check custom choices differently...
3162 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
3163 (coption
= ppdFindCustomOption(ppd
,
3164 option
->keyword
)) != NULL
)
3166 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
3167 language
, option
->keyword
);
3169 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
3170 !valid_utf8(attr
->text
))
3172 if (!warn
&& !errors
&& !verbose
)
3173 _cupsLangPuts(stdout
, _(" FAIL\n"));
3176 _cupsLangPrintf(stdout
,
3177 _(" %s Bad UTF-8 \"%s\" "
3178 "translation string for option %s, "
3181 ckeyword
+ 1 + strlen(language
),
3188 if (strcasecmp(option
->keyword
, "PageSize"))
3190 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
3192 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
3194 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
3195 language
, option
->keyword
);
3196 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
3197 ll
, option
->keyword
);
3199 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
3200 cparam
->name
)) == NULL
&&
3201 (attr
= ppdFindAttr(ppd
, cllkeyword
,
3202 cparam
->name
)) == NULL
)
3204 if (!warn
&& !errors
&& !verbose
)
3205 _cupsLangPuts(stdout
, _(" FAIL\n"));
3208 _cupsLangPrintf(stdout
,
3209 _(" %s Missing \"%s\" "
3210 "translation string for option %s, "
3213 ckeyword
+ 1 + strlen(language
),
3219 else if (!valid_utf8(attr
->text
))
3221 if (!warn
&& !errors
&& !verbose
)
3222 _cupsLangPuts(stdout
, _(" FAIL\n"));
3225 _cupsLangPrintf(stdout
,
3226 _(" %s Bad UTF-8 \"%s\" "
3227 "translation string for option %s, "
3230 ckeyword
+ 1 + strlen(language
),
3239 else if ((attr
= ppdFindAttr(ppd
, keyword
,
3240 option
->choices
[j
].choice
)) == NULL
&&
3241 (attr
= ppdFindAttr(ppd
, llkeyword
,
3242 option
->choices
[j
].choice
)) == NULL
)
3244 if (!warn
&& !errors
&& !verbose
)
3245 _cupsLangPuts(stdout
, _(" FAIL\n"));
3248 _cupsLangPrintf(stdout
,
3249 _(" %s Missing \"%s\" "
3250 "translation string for option %s, "
3252 prefix
, language
, option
->keyword
,
3253 option
->choices
[j
].choice
);
3258 else if (!valid_utf8(attr
->text
))
3260 if (!warn
&& !errors
&& !verbose
)
3261 _cupsLangPuts(stdout
, _(" FAIL\n"));
3264 _cupsLangPrintf(stdout
,
3265 _(" %s Bad UTF-8 \"%s\" "
3266 "translation string for option %s, "
3268 prefix
, language
, option
->keyword
,
3269 option
->choices
[j
].choice
);
3279 * Verify that we have the base language for each localized one...
3282 for (language
= (char *)cupsArrayFirst(languages
);
3284 language
= (char *)cupsArrayNext(languages
))
3288 * Lookup the base language...
3291 cupsArraySave(languages
);
3293 strlcpy(ll
, language
, sizeof(ll
));
3295 if (!cupsArrayFind(languages
, ll
) &&
3296 strcmp(ll
, "zh") && strcmp(ll
, "en"))
3298 if (!warn
&& !errors
&& !verbose
)
3299 _cupsLangPuts(stdout
, _(" FAIL\n"));
3302 _cupsLangPrintf(stdout
,
3303 _(" %s No base translation \"%s\" "
3304 "is included in file!\n"), prefix
, ll
);
3310 cupsArrayRestore(languages
);
3314 * Free memory used for the languages...
3317 _ppdFreeLanguages(languages
);
3325 * 'show_conflicts()' - Show option conflicts in a PPD file.
3329 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
3331 int i
, j
; /* Looping variables */
3332 ppd_const_t
*c
; /* Current constraint */
3333 ppd_option_t
*o1
, *o2
; /* Options */
3334 ppd_choice_t
*c1
, *c2
; /* Choices */
3338 * Loop through all of the UI constraints and report any options
3342 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
3345 * Grab pointers to the first option...
3348 o1
= ppdFindOption(ppd
, c
->option1
);
3352 else if (c
->choice1
[0] != '\0')
3355 * This constraint maps to a specific choice.
3358 c1
= ppdFindChoice(o1
, c
->choice1
);
3363 * This constraint applies to any choice for this option.
3366 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
3371 !strcasecmp(c1
->choice
, "None") ||
3372 !strcasecmp(c1
->choice
, "Off") ||
3373 !strcasecmp(c1
->choice
, "False"))
3378 * Grab pointers to the second option...
3381 o2
= ppdFindOption(ppd
, c
->option2
);
3385 else if (c
->choice2
[0] != '\0')
3388 * This constraint maps to a specific choice.
3391 c2
= ppdFindChoice(o2
, c
->choice2
);
3396 * This constraint applies to any choice for this option.
3399 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
3404 !strcasecmp(c2
->choice
, "None") ||
3405 !strcasecmp(c2
->choice
, "Off") ||
3406 !strcasecmp(c2
->choice
, "False"))
3411 * If both options are marked then there is a conflict...
3414 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
3415 _cupsLangPrintf(stdout
,
3416 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
3417 " (constraint=\"%s %s %s %s\")\n"),
3418 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
3419 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
3425 * 'test_raster()' - Test PostScript commands for raster printers.
3428 static int /* O - 1 on success, 0 on failure */
3429 test_raster(ppd_file_t
*ppd
, /* I - PPD file */
3430 int verbose
) /* I - Verbosity */
3432 cups_page_header2_t header
; /* Page header */
3435 ppdMarkDefaults(ppd
);
3436 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3439 _cupsLangPuts(stdout
, _(" FAIL\n"));
3442 _cupsLangPrintf(stdout
,
3443 _(" **FAIL** Default option code cannot be "
3444 "interpreted: %s\n"), cupsRasterErrorString());
3450 * Try a test of custom page size code, if available...
3453 if (!ppdPageSize(ppd
, "Custom.612x792"))
3456 ppdMarkOption(ppd
, "PageSize", "Custom.612x792");
3458 if (cupsRasterInterpretPPD(&header
, ppd
, 0, NULL
, 0))
3461 _cupsLangPuts(stdout
, _(" FAIL\n"));
3464 _cupsLangPrintf(stdout
,
3465 _(" **FAIL** Default option code cannot be "
3466 "interpreted: %s\n"), cupsRasterErrorString());
3476 * 'usage()' - Show program usage...
3482 _cupsLangPuts(stdout
,
3483 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
3484 "[... filenameN.ppd[.gz]]\n"
3485 " program | cupstestppd [options] -\n"
3489 " -R root-directory Set alternate root\n"
3490 " -W {all,none,constraints,defaults,duplex,filters,"
3491 "profiles,sizes,translations}\n"
3492 " Issue warnings instead of errors\n"
3493 " -q Run silently\n"
3494 " -r Use 'relaxed' open mode\n"
3495 " -v Be slightly verbose\n"
3496 " -vv Be very verbose\n"));
3503 * 'valid_path()' - Check whether a path has the correct capitalization.
3506 static int /* O - Errors found */
3507 valid_path(const char *keyword
, /* I - Keyword using path */
3508 const char *path
, /* I - Path to check */
3509 int errors
, /* I - Errors found */
3510 int verbose
, /* I - Verbosity level */
3511 int warn
) /* I - Warnings only? */
3513 cups_dir_t
*dir
; /* Current directory */
3514 cups_dentry_t
*dentry
; /* Current directory entry */
3515 char temp
[1024], /* Temporary path */
3516 *ptr
; /* Pointer into temporary path */
3517 const char *prefix
; /* WARN/FAIL prefix */
3520 prefix
= warn
? " WARN " : "**FAIL**";
3523 * Loop over the components of the path, checking that the entry exists with
3524 * the same capitalization...
3527 strlcpy(temp
, path
, sizeof(temp
));
3529 while ((ptr
= strrchr(temp
, '/')) != NULL
)
3532 * Chop off the trailing component so temp == dirname and ptr == basename.
3538 * Try opening the directory containing the base name...
3542 dir
= cupsDirOpen(temp
);
3544 dir
= cupsDirOpen("/");
3550 while ((dentry
= cupsDirRead(dir
)) != NULL
)
3552 if (!strcmp(dentry
->filename
, ptr
))
3560 * Display an error if the filename doesn't exist with the same
3566 if (!warn
&& !errors
&& !verbose
)
3567 _cupsLangPuts(stdout
, _(" FAIL\n"));
3570 _cupsLangPrintf(stdout
,
3571 _(" %s %s file \"%s\" has the wrong "
3572 "capitalization!\n"), prefix
, keyword
, path
);
3586 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3589 static int /* O - 1 if valid, 0 if not */
3590 valid_utf8(const char *s
) /* I - String to check */
3597 * Check for valid UTF-8 sequence...
3600 if ((*s
& 0xc0) == 0x80)
3601 return (0); /* Illegal suffix byte */
3602 else if ((*s
& 0xe0) == 0xc0)
3605 * 2-byte sequence...
3610 if ((*s
& 0xc0) != 0x80)
3611 return (0); /* Missing suffix byte */
3613 else if ((*s
& 0xf0) == 0xe0)
3616 * 3-byte sequence...
3621 if ((*s
& 0xc0) != 0x80)
3622 return (0); /* Missing suffix byte */
3626 if ((*s
& 0xc0) != 0x80)
3627 return (0); /* Missing suffix byte */
3629 else if ((*s
& 0xf8) == 0xf0)
3632 * 4-byte sequence...
3637 if ((*s
& 0xc0) != 0x80)
3638 return (0); /* Missing suffix byte */
3642 if ((*s
& 0xc0) != 0x80)
3643 return (0); /* Missing suffix byte */
3647 if ((*s
& 0xc0) != 0x80)
3648 return (0); /* Missing suffix byte */
3651 return (0); /* Bad sequence */
3662 * End of "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $".