2 * "$Id: cupstestppd.c 5926 2006-09-05 20:45:47Z mike $"
4 * PPD test program for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * PostScript is a trademark of Adobe Systems, Inc.
26 * This file is subject to the Apple OS-Developed Software exception.
30 * main() - Main entry for test program.
31 * show_conflicts() - Show option conflicts in a PPD file.
32 * usage() - Show program usage...
36 * Include necessary headers...
39 #include <cups/string.h>
40 #include <cups/cups.h>
41 #include <cups/i18n.h>
77 void check_basics(const char *filename
);
78 void show_conflicts(ppd_file_t
*ppd
);
83 * 'main()' - Main entry for test program.
86 int /* O - Exit status */
87 main(int argc
, /* I - Number of command-line arguments */
88 char *argv
[]) /* I - Command-line arguments */
90 int i
, j
, k
, m
, n
; /* Looping vars */
91 int len
; /* Length of option name */
92 char *opt
; /* Option character */
93 const char *ptr
; /* Pointer into string */
94 int files
; /* Number of files */
95 int verbose
; /* Want verbose output? */
96 int status
; /* Exit status */
97 int errors
; /* Number of conformance errors */
98 int ppdversion
; /* PPD spec version in PPD file */
99 ppd_status_t error
; /* Status of ppdOpen*() */
100 int line
; /* Line number for error */
101 int xdpi
, /* X resolution */
102 ydpi
; /* Y resolution */
103 ppd_file_t
*ppd
; /* PPD file record */
104 ppd_attr_t
*attr
; /* PPD attribute */
105 ppd_size_t
*size
; /* Size record */
106 ppd_group_t
*group
; /* UI group */
107 ppd_option_t
*option
; /* Standard UI option */
108 ppd_group_t
*group2
; /* UI group */
109 ppd_option_t
*option2
; /* Standard UI option */
110 ppd_choice_t
*choice
; /* Standard UI option choice */
111 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
112 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
113 "JCL", "PAGE", "PROLOG" };
116 _cupsSetLocale(argv
);
119 * Display PPD files for each file listed on the command-line...
122 ppdSetConformance(PPD_CONFORM_STRICT
);
129 for (i
= 1; i
< argc
; i
++)
130 if (argv
[i
][0] == '-' && argv
[i
][1])
132 for (opt
= argv
[i
] + 1; *opt
; opt
++)
135 case 'q' : /* Quiet mode */
138 _cupsLangPuts(stderr
,
139 _("cupstestppd: The -q option is incompatible "
140 "with the -v option.\n"));
147 case 'r' : /* Relaxed mode */
148 ppdSetConformance(PPD_CONFORM_RELAXED
);
151 case 'v' : /* Verbose mode */
154 _cupsLangPuts(stderr
,
155 _("cupstestppd: The -v option is incompatible "
156 "with the -q option.\n"));
171 * Open the PPD file...
174 if (files
&& verbose
>= 0)
175 _cupsLangPuts(stdout
, "\n");
179 if (argv
[i
][0] == '-')
188 ppd
= ppdOpen(stdin
);
193 * Read from a file...
197 printf("%s:", argv
[i
]);
199 ppd
= ppdOpenFile(argv
[i
]);
204 error
= ppdLastError(&line
);
206 if (error
<= PPD_ALLOC_ERROR
)
208 status
= ERROR_FILE_OPEN
;
211 _cupsLangPrintf(stdout
,
213 " **FAIL** Unable to open PPD file - %s\n"),
218 status
= ERROR_PPD_FORMAT
;
222 _cupsLangPrintf(stdout
,
224 " **FAIL** Unable to open PPD file - "
226 ppdErrorString(error
), line
);
230 case PPD_MISSING_PPDADOBE4
:
231 _cupsLangPuts(stdout
,
232 _(" REF: Page 42, section 5.2.\n"));
234 case PPD_MISSING_VALUE
:
235 _cupsLangPuts(stdout
,
236 _(" REF: Page 20, section 3.4.\n"));
238 case PPD_BAD_OPEN_GROUP
:
239 case PPD_NESTED_OPEN_GROUP
:
240 _cupsLangPuts(stdout
,
241 _(" REF: Pages 45-46, section 5.2.\n"));
243 case PPD_BAD_OPEN_UI
:
244 case PPD_NESTED_OPEN_UI
:
245 _cupsLangPuts(stdout
,
246 _(" REF: Pages 42-45, section 5.2.\n"));
248 case PPD_BAD_ORDER_DEPENDENCY
:
249 _cupsLangPuts(stdout
,
250 _(" REF: Pages 48-49, section 5.2.\n"));
252 case PPD_BAD_UI_CONSTRAINTS
:
253 _cupsLangPuts(stdout
,
254 _(" REF: Pages 52-54, section 5.2.\n"));
256 case PPD_MISSING_ASTERISK
:
257 _cupsLangPuts(stdout
,
258 _(" REF: Page 15, section 3.2.\n"));
260 case PPD_LINE_TOO_LONG
:
261 _cupsLangPuts(stdout
,
262 _(" REF: Page 15, section 3.1.\n"));
264 case PPD_ILLEGAL_CHARACTER
:
265 _cupsLangPuts(stdout
,
266 _(" REF: Page 15, section 3.1.\n"));
268 case PPD_ILLEGAL_MAIN_KEYWORD
:
269 _cupsLangPuts(stdout
,
270 _(" REF: Pages 16-17, section 3.2.\n"));
272 case PPD_ILLEGAL_OPTION_KEYWORD
:
273 _cupsLangPuts(stdout
,
274 _(" REF: Page 19, section 3.3.\n"));
276 case PPD_ILLEGAL_TRANSLATION
:
277 _cupsLangPuts(stdout
,
278 _(" REF: Page 27, section 3.5.\n"));
284 check_basics(argv
[i
]);
292 * Show the header and then perform basic conformance tests (limited
293 * only by what the CUPS PPD functions actually load...)
300 _cupsLangPuts(stdout
,
301 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
303 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
305 ppdversion
= (int)(10 * atof(attr
->value
) + 0.5);
308 * Look for default keywords with no matching option...
311 for (j
= 0; j
< ppd
->num_attrs
; j
++)
313 attr
= ppd
->attrs
[j
];
315 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
316 !strcmp(attr
->name
, "DefaultFont") ||
317 !strcmp(attr
->name
, "DefaultImageableArea") ||
318 !strcmp(attr
->name
, "DefaultOutputOrder") ||
319 !strcmp(attr
->name
, "DefaultPaperDimension") ||
320 !strcmp(attr
->name
, "DefaultTransfer"))
323 if (!strncmp(attr
->name
, "Default", 7))
325 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
326 strcmp(attr
->value
, "Unknown"))
329 * Check that the default option value matches a choice...
332 for (k
= 0; k
< option
->num_choices
; k
++)
333 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
336 if (k
>= option
->num_choices
)
340 if (!errors
&& !verbose
)
341 _cupsLangPuts(stdout
, _(" FAIL\n"));
343 _cupsLangPrintf(stdout
,
344 _(" **FAIL** %s %s does not exist!\n"),
345 attr
->name
, attr
->value
);
354 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
358 if (!errors
&& !verbose
)
359 _cupsLangPuts(stdout
, _(" FAIL\n"));
361 _cupsLangPuts(stdout
,
362 _(" **FAIL** REQUIRED DefaultImageableArea\n"
363 " REF: Page 102, section 5.15.\n"));
368 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
369 strcmp(attr
->value
, "Unknown"))
373 if (!errors
&& !verbose
)
374 _cupsLangPuts(stdout
, _(" FAIL\n"));
376 _cupsLangPrintf(stdout
,
377 _(" **FAIL** BAD DefaultImageableArea %s!\n"
378 " REF: Page 102, section 5.15.\n"),
387 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
390 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
394 if (!errors
&& !verbose
)
395 _cupsLangPuts(stdout
, _(" FAIL\n"));
397 _cupsLangPuts(stdout
,
398 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
399 " REF: Page 103, section 5.15.\n"));
404 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
405 strcmp(attr
->value
, "Unknown"))
409 if (!errors
&& !verbose
)
410 _cupsLangPuts(stdout
, _(" FAIL\n"));
412 _cupsLangPrintf(stdout
,
413 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
414 " REF: Page 103, section 5.15.\n"),
420 else if (verbose
> 0)
421 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
423 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
424 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
427 * Verify that we have a default choice...
430 if (option
->defchoice
[0])
432 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
433 strcmp(option
->defchoice
, "Unknown"))
437 if (!errors
&& !verbose
)
438 _cupsLangPuts(stdout
, _(" FAIL\n"));
440 _cupsLangPrintf(stdout
,
441 _(" **FAIL** BAD Default%s %s\n"
442 " REF: Page 40, section 4.5.\n"),
443 option
->keyword
, option
->defchoice
);
448 else if (verbose
> 0)
449 _cupsLangPrintf(stdout
,
450 _(" PASS Default%s\n"),
457 if (!errors
&& !verbose
)
458 _cupsLangPuts(stdout
, _(" FAIL\n"));
460 _cupsLangPrintf(stdout
,
461 _(" **FAIL** REQUIRED Default%s\n"
462 " REF: Page 40, section 4.5.\n"),
470 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
473 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
479 if (!errors
&& !verbose
)
480 _cupsLangPuts(stdout
, _(" FAIL\n"));
482 _cupsLangPuts(stdout
,
483 _(" **FAIL** REQUIRED FileVersion\n"
484 " REF: Page 56, section 5.3.\n"));
490 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
493 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
499 if (!errors
&& !verbose
)
500 _cupsLangPuts(stdout
, _(" FAIL\n"));
502 _cupsLangPuts(stdout
,
503 _(" **FAIL** REQUIRED FormatVersion\n"
504 " REF: Page 56, section 5.3.\n"));
510 if (ppd
->lang_encoding
!= NULL
)
513 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
515 else if (ppdversion
> 40)
519 if (!errors
&& !verbose
)
520 _cupsLangPuts(stdout
, _(" FAIL\n"));
522 _cupsLangPuts(stdout
,
523 _(" **FAIL** REQUIRED LanguageEncoding\n"
524 " REF: Pages 56-57, section 5.3.\n"));
530 if (ppd
->lang_version
!= NULL
)
533 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
539 if (!errors
&& !verbose
)
540 _cupsLangPuts(stdout
, _(" FAIL\n"));
542 _cupsLangPuts(stdout
,
543 _(" **FAIL** REQUIRED LanguageVersion\n"
544 " REF: Pages 57-58, section 5.3.\n"));
550 if (ppd
->manufacturer
!= NULL
)
552 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
553 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
557 if (!errors
&& !verbose
)
558 _cupsLangPuts(stdout
, _(" FAIL\n"));
560 _cupsLangPuts(stdout
,
561 _(" **FAIL** BAD Manufacturer (should be "
563 " REF: Page 211, table D.1.\n"));
568 else if (verbose
> 0)
569 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
571 else if (ppdversion
>= 43)
575 if (!errors
&& !verbose
)
576 _cupsLangPuts(stdout
, _(" FAIL\n"));
578 _cupsLangPuts(stdout
,
579 _(" **FAIL** REQUIRED Manufacturer\n"
580 " REF: Pages 58-59, section 5.3.\n"));
586 if (ppd
->modelname
!= NULL
)
588 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
589 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
596 if (!errors
&& !verbose
)
597 _cupsLangPuts(stdout
, _(" FAIL\n"));
599 _cupsLangPrintf(stdout
,
600 _(" **FAIL** BAD ModelName - \"%c\" not "
601 "allowed in string.\n"
602 " REF: Pages 59-60, section 5.3.\n"),
608 else if (verbose
> 0)
609 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
615 if (!errors
&& !verbose
)
616 _cupsLangPuts(stdout
, _(" FAIL\n"));
618 _cupsLangPuts(stdout
,
619 _(" **FAIL** REQUIRED ModelName\n"
620 " REF: Pages 59-60, section 5.3.\n"));
626 if (ppd
->nickname
!= NULL
)
629 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
635 if (!errors
&& !verbose
)
636 _cupsLangPuts(stdout
, _(" FAIL\n"));
638 _cupsLangPuts(stdout
,
639 _(" **FAIL** REQUIRED NickName\n"
640 " REF: Page 60, section 5.3.\n"));
646 if (ppdFindOption(ppd
, "PageSize") != NULL
)
649 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
655 if (!errors
&& !verbose
)
656 _cupsLangPuts(stdout
, _(" FAIL\n"));
658 _cupsLangPuts(stdout
,
659 _(" **FAIL** REQUIRED PageSize\n"
660 " REF: Pages 99-100, section 5.14.\n"));
666 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
669 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
675 if (!errors
&& !verbose
)
676 _cupsLangPuts(stdout
, _(" FAIL\n"));
678 _cupsLangPuts(stdout
,
679 _(" **FAIL** REQUIRED PageRegion\n"
680 " REF: Page 100, section 5.14.\n"));
686 if (ppd
->pcfilename
!= NULL
)
689 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
695 if (!errors
&& !verbose
)
696 _cupsLangPuts(stdout
, _(" FAIL\n"));
698 _cupsLangPuts(stdout
,
699 _(" **FAIL** REQUIRED PCFileName\n"
700 " REF: Pages 61-62, section 5.3.\n"));
706 if (ppd
->product
!= NULL
)
708 if (ppd
->product
[0] != '(' ||
709 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
713 if (!errors
&& !verbose
)
714 _cupsLangPuts(stdout
, _(" FAIL\n"));
716 _cupsLangPuts(stdout
,
717 _(" **FAIL** BAD Product - not \"(string)\".\n"
718 " REF: Page 62, section 5.3.\n"));
723 else if (verbose
> 0)
724 _cupsLangPuts(stdout
, _(" PASS Product\n"));
730 if (!errors
&& !verbose
)
731 _cupsLangPuts(stdout
, _(" FAIL\n"));
733 _cupsLangPuts(stdout
,
734 _(" **FAIL** REQUIRED Product\n"
735 " REF: Page 62, section 5.3.\n"));
741 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
744 char junkstr
[255]; /* Temp string */
745 int junkint
; /* Temp integer */
748 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
752 if (!errors
&& !verbose
)
753 _cupsLangPuts(stdout
, _(" FAIL\n"));
755 _cupsLangPuts(stdout
,
756 _(" **FAIL** BAD PSVersion - not \"(string) "
758 " REF: Pages 62-64, section 5.3.\n"));
763 else if (verbose
> 0)
764 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
770 if (!errors
&& !verbose
)
771 _cupsLangPuts(stdout
, _(" FAIL\n"));
773 _cupsLangPuts(stdout
,
774 _(" **FAIL** REQUIRED PSVersion\n"
775 " REF: Pages 62-64, section 5.3.\n"));
781 if (ppd
->shortnickname
!= NULL
)
783 if (strlen(ppd
->shortnickname
) > 31)
787 if (!errors
&& !verbose
)
788 _cupsLangPuts(stdout
, _(" FAIL\n"));
790 _cupsLangPuts(stdout
,
791 _(" **FAIL** BAD ShortNickName - longer "
793 " REF: Pages 64-65, section 5.3.\n"));
798 else if (verbose
> 0)
799 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
801 else if (ppdversion
>= 43)
805 if (!errors
&& !verbose
)
806 _cupsLangPuts(stdout
, _(" FAIL\n"));
808 _cupsLangPuts(stdout
,
809 _(" **FAIL** REQUIRED ShortNickName\n"
810 " REF: Page 64-65, section 5.3.\n"));
816 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
817 strstr(ppd
->patches
, "*End"))
821 if (!errors
&& !verbose
)
822 _cupsLangPuts(stdout
, _(" FAIL\n"));
824 _cupsLangPuts(stdout
,
825 _(" **FAIL** BAD JobPatchFile attribute in file\n"
826 " REF: Page 24, section 3.4.\n"));
833 * Check for page sizes without the corresponding ImageableArea or
834 * PaperDimension values...
837 if (ppd
->num_sizes
== 0)
841 if (!errors
&& !verbose
)
842 _cupsLangPuts(stdout
, _(" FAIL\n"));
844 _cupsLangPuts(stdout
,
845 _(" **FAIL** REQUIRED PageSize\n"
846 " REF: Page 41, section 5.\n"
847 " REF: Page 99, section 5.14.\n"));
854 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
857 * Don't check custom size...
860 if (!strcmp(size
->name
, "Custom"))
864 * Check for ImageableArea...
867 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
868 size
->right
== 0.0 && size
->top
== 0.0)
872 if (!errors
&& !verbose
)
873 _cupsLangPuts(stdout
, _(" FAIL\n"));
875 _cupsLangPrintf(stdout
,
876 _(" **FAIL** REQUIRED ImageableArea for "
878 " REF: Page 41, section 5.\n"
879 " REF: Page 102, section 5.15.\n"),
887 * Check for PaperDimension...
890 if (size
->width
== 0.0 && size
->length
== 0.0)
894 if (!errors
&& !verbose
)
895 _cupsLangPuts(stdout
, _(" FAIL\n"));
897 _cupsLangPrintf(stdout
,
898 _(" **FAIL** REQUIRED PaperDimension "
900 " REF: Page 41, section 5.\n"
901 " REF: Page 103, section 5.15.\n"),
911 * Check for valid Resolution, JCLResolution, or SetResolution values...
914 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
915 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
916 option
= ppdFindOption(ppd
, "SetResolution");
920 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
923 * Verify that all resolution options are of the form NNNdpi
927 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
928 if (ptr
> choice
->choice
&& xdpi
> 0)
931 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
938 if (xdpi
<= 0 || ydpi
<= 0 || strcmp(ptr
, "dpi"))
942 if (!errors
&& !verbose
)
943 _cupsLangPuts(stdout
, _(" FAIL\n"));
945 _cupsLangPrintf(stdout
,
946 _(" **FAIL** Bad %s choice %s!\n"
947 " REF: Page 84, section 5.9\n"),
948 option
->keyword
, choice
->choice
);
957 * Check for a duplex option, and for standard values...
960 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
961 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
962 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
963 option
= ppdFindOption(ppd
, "KD03Duplex");
967 if (ppdFindChoice(option
, "None") == NULL
)
971 if (!errors
&& !verbose
)
972 _cupsLangPuts(stdout
, _(" FAIL\n"));
974 _cupsLangPrintf(stdout
,
975 _(" **FAIL** REQUIRED %s does not define "
977 " REF: Page 122, section 5.17\n"),
984 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
985 if (strcmp(choice
->choice
, "None") &&
986 strcmp(choice
->choice
, "DuplexNoTumble") &&
987 strcmp(choice
->choice
, "DuplexTumble") &&
988 strcmp(choice
->choice
, "SimplexTumble"))
992 if (!errors
&& !verbose
)
993 _cupsLangPuts(stdout
, _(" FAIL\n"));
995 _cupsLangPrintf(stdout
,
996 _(" **FAIL** Bad %s choice %s!\n"
997 " REF: Page 122, section 5.17\n"),
998 option
->keyword
, choice
->choice
);
1005 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1009 * This file contains localizations, check them...
1012 char *languages
, /* Copy of attribute value */
1013 *langstart
, /* Start of current language */
1014 *langptr
, /* Pointer into languages */
1015 keyword
[PPD_MAX_NAME
], /* Localization keyword */
1016 ckeyword
[PPD_MAX_NAME
]; /* Custom option keyword */
1017 ppd_coption_t
*coption
; /* Custom option */
1018 ppd_cparam_t
*cparam
; /* Custom parameter */
1021 languages
= strdup(attr
->value
);
1022 for (langptr
= languages
; *langptr
;)
1025 * Skip leading whitespace...
1028 while (isspace(*langptr
& 255))
1035 * Find the end of this language name...
1038 for (langstart
= langptr
;
1039 *langptr
&& !isspace(*langptr
& 255);
1045 j
= strlen(langstart
);
1046 if (j
!= 2 && j
!= 5)
1050 if (!errors
&& !verbose
)
1051 _cupsLangPuts(stdout
, _(" FAIL\n"));
1053 _cupsLangPrintf(stdout
,
1054 _(" **FAIL** Bad language \"%s\"!\n"),
1063 * Loop through all options and choices...
1066 for (option
= ppdFirstOption(ppd
);
1068 option
= ppdNextOption(ppd
))
1070 snprintf(keyword
, sizeof(keyword
), "%s.Translation", langstart
);
1071 if (!ppdFindAttr(ppd
, keyword
, option
->keyword
))
1075 if (!errors
&& !verbose
)
1076 _cupsLangPuts(stdout
, _(" FAIL\n"));
1078 _cupsLangPrintf(stdout
,
1079 _(" **FAIL** Missing \"%s\" translation "
1080 "string for option %s!\n"),
1081 langstart
, option
->keyword
);
1087 for (ptr
= option
->text
; *ptr
; ptr
++)
1095 if (!errors
&& !verbose
)
1096 _cupsLangPuts(stdout
, _(" FAIL\n"));
1098 _cupsLangPrintf(stdout
,
1099 _(" **FAIL** Default translation "
1100 "string for option %s contains 8-bit "
1108 snprintf(keyword
, sizeof(keyword
), "%s.%s", langstart
,
1110 for (j
= 0; j
< option
->num_choices
; j
++)
1112 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
1113 (coption
= ppdFindCustomOption(ppd
,
1114 option
->keyword
)) != NULL
)
1116 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
1117 langstart
, option
->keyword
);
1119 if (!ppdFindAttr(ppd
, ckeyword
, "True"))
1123 if (!errors
&& !verbose
)
1124 _cupsLangPuts(stdout
, _(" FAIL\n"));
1126 _cupsLangPrintf(stdout
,
1127 _(" **FAIL** Missing \"%s\" "
1128 "translation string for option %s, "
1130 langstart
, ckeyword
+ 1 + strlen(langstart
),
1137 if (strcasecmp(option
->keyword
, "PageSize"))
1139 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
1141 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
1143 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
1144 langstart
, option
->keyword
);
1145 if (!ppdFindAttr(ppd
, ckeyword
, cparam
->name
))
1149 if (!errors
&& !verbose
)
1150 _cupsLangPuts(stdout
, _(" FAIL\n"));
1152 _cupsLangPrintf(stdout
,
1153 _(" **FAIL** Missing \"%s\" "
1154 "translation string for option %s, "
1157 ckeyword
+ 1 + strlen(langstart
),
1166 else if (!ppdFindAttr(ppd
, keyword
, option
->choices
[j
].choice
))
1170 if (!errors
&& !verbose
)
1171 _cupsLangPuts(stdout
, _(" FAIL\n"));
1173 _cupsLangPrintf(stdout
,
1174 _(" **FAIL** Missing \"%s\" "
1175 "translation string for option %s, "
1177 langstart
, option
->keyword
,
1178 option
->choices
[j
].choice
);
1184 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1192 if (!errors
&& !verbose
)
1193 _cupsLangPuts(stdout
, _(" FAIL\n"));
1195 _cupsLangPrintf(stdout
,
1196 _(" **FAIL** Default translation "
1197 "string for option %s choice %s contains "
1198 "8-bit characters!\n"),
1200 option
->choices
[j
].choice
);
1210 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
1212 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
1214 char super
[16], /* Filter super type */
1215 type
[256], /* Filter type */
1216 program
[256]; /* Filter program */
1217 int cost
; /* Filter cost */
1221 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1226 if (!errors
&& !verbose
)
1227 _cupsLangPuts(stdout
, _(" FAIL\n"));
1229 _cupsLangPrintf(stdout
,
1230 _(" **FAIL** Bad cupsFilter value \"%s\"!\n"),
1231 attr
->value
? attr
->value
: "");
1238 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1239 strcmp(attr
->name
, "1284DeviceID"))
1243 if (!errors
&& !verbose
)
1244 _cupsLangPuts(stdout
, _(" FAIL\n"));
1246 _cupsLangPrintf(stdout
,
1247 _(" **FAIL** %s must be 1284DeviceID!\n"
1248 " REF: Page 72, section 5.5\n"),
1256 status
= ERROR_CONFORMANCE
;
1258 _cupsLangPuts(stdout
, _(" PASS\n"));
1262 check_basics(argv
[i
]);
1265 * Look for default keywords with no corresponding option...
1268 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1270 attr
= ppd
->attrs
[j
];
1272 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1273 !strcmp(attr
->name
, "DefaultColorSep") ||
1274 !strcmp(attr
->name
, "DefaultFont") ||
1275 !strcmp(attr
->name
, "DefaultImageableArea") ||
1276 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1277 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1278 !strcmp(attr
->name
, "DefaultScreenProc") ||
1279 !strcmp(attr
->name
, "DefaultTransfer"))
1282 if (!strncmp(attr
->name
, "Default", 7) &&
1283 !ppdFindOption(ppd
, attr
->name
+ 7))
1284 _cupsLangPrintf(stdout
,
1285 _(" WARN %s has no corresponding "
1291 * Check for old Duplex option names...
1294 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1295 option
= ppdFindOption(ppd
, "KD03Duplex");
1299 _cupsLangPrintf(stdout
,
1300 _(" WARN Duplex option keyword %s "
1301 "should be named Duplex or JCLDuplex!\n"
1302 " REF: Page 122, section 5.17\n"),
1306 ppdMarkDefaults(ppd
);
1307 if (ppdConflicts(ppd
))
1309 _cupsLangPuts(stdout
,
1310 _(" WARN Default choices conflicting!\n"));
1312 show_conflicts(ppd
);
1315 if (ppdversion
< 43)
1317 _cupsLangPrintf(stdout
,
1318 _(" WARN Obsolete PPD version %.1f!\n"
1319 " REF: Page 42, section 5.2.\n"),
1323 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1325 _cupsLangPuts(stdout
,
1326 _(" WARN LanguageEncoding required by PPD "
1328 " REF: Pages 56-57, section 5.3.\n"));
1331 if (!ppd
->manufacturer
&& ppdversion
< 43)
1333 _cupsLangPuts(stdout
,
1334 _(" WARN Manufacturer required by PPD "
1336 " REF: Pages 58-59, section 5.3.\n"));
1340 * Treat a PCFileName attribute longer than 12 characters as
1341 * a warning and not a hard error...
1344 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1346 _cupsLangPuts(stdout
,
1347 _(" WARN PCFileName longer than 8.3 in "
1348 "violation of PPD spec.\n"
1349 " REF: Pages 61-62, section 5.3.\n"));
1352 if (!ppd
->shortnickname
&& ppdversion
< 43)
1354 _cupsLangPuts(stdout
,
1355 _(" WARN ShortNickName required by PPD "
1357 " REF: Pages 64-65, section 5.3.\n"));
1361 * Check the Protocols line and flag PJL + BCP since TBCP is
1362 * usually used with PJL...
1367 if (strstr(ppd
->protocols
, "PJL") &&
1368 strstr(ppd
->protocols
, "BCP") &&
1369 !strstr(ppd
->protocols
, "TBCP"))
1371 _cupsLangPuts(stdout
,
1372 _(" WARN Protocols contains both PJL "
1373 "and BCP; expected TBCP.\n"
1374 " REF: Pages 78-79, section 5.7.\n"));
1377 if (strstr(ppd
->protocols
, "PJL") &&
1378 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1380 _cupsLangPuts(stdout
,
1381 _(" WARN Protocols contains PJL but JCL "
1382 "attributes are not set.\n"
1383 " REF: Pages 78-79, section 5.7.\n"));
1388 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1389 * which are errors according to the spec but won't cause problems
1390 * with CUPS specifically...
1393 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1394 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1396 len
= strlen(option
->keyword
);
1398 for (m
= 0, group2
= ppd
->groups
;
1399 m
< ppd
->num_groups
;
1401 for (n
= 0, option2
= group2
->options
;
1402 n
< group2
->num_options
;
1404 if (option
!= option2
&&
1405 len
< strlen(option2
->keyword
) &&
1406 !strncmp(option
->keyword
, option2
->keyword
, len
))
1408 _cupsLangPrintf(stdout
,
1409 _(" WARN %s shares a common "
1411 " REF: Page 15, section "
1413 option
->keyword
, option2
->keyword
);
1421 _cupsLangPrintf(stdout
, _(" %d ERROR%s FOUND\n"),
1422 errors
, errors
== 1 ? "" : "S");
1424 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1428 * Then list the options, if "-v" was provided...
1433 _cupsLangPrintf(stdout
,
1435 " language_level = %d\n"
1436 " color_device = %s\n"
1437 " variable_sizes = %s\n"
1438 " landscape = %d\n",
1439 ppd
->language_level
,
1440 ppd
->color_device
? "TRUE" : "FALSE",
1441 ppd
->variable_sizes
? "TRUE" : "FALSE",
1444 switch (ppd
->colorspace
)
1447 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1450 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1453 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1456 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1459 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1463 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1464 ppd
->num_emulations
);
1465 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1466 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1467 j
, ppd
->emulations
[j
].name
);
1469 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1470 ppd
->lang_encoding
);
1471 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1473 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1474 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1475 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1476 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1478 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1479 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1480 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1481 ppd
->shortnickname
);
1482 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1483 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1485 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1486 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1488 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1491 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1493 _cupsLangPrintf(stdout
,
1494 " options[%d] = %s (%s) %s %s %.0f "
1496 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1497 sections
[option
->section
], option
->order
,
1498 option
->num_choices
);
1500 if (!strcmp(option
->keyword
, "PageSize") ||
1501 !strcmp(option
->keyword
, "PageRegion"))
1503 for (m
= option
->num_choices
, choice
= option
->choices
;
1507 size
= ppdPageSize(ppd
, choice
->choice
);
1510 _cupsLangPrintf(stdout
,
1512 choice
->choice
, choice
->text
);
1514 _cupsLangPrintf(stdout
,
1515 " %s (%s) = %.2fx%.2fin "
1516 "(%.1f,%.1f,%.1f,%.1f)",
1517 choice
->choice
, choice
->text
,
1518 size
->width
/ 72.0, size
->length
/ 72.0,
1519 size
->left
/ 72.0, size
->bottom
/ 72.0,
1520 size
->right
/ 72.0, size
->top
/ 72.0);
1522 if (!strcmp(option
->defchoice
, choice
->choice
))
1523 _cupsLangPuts(stdout
, " *\n");
1525 _cupsLangPuts(stdout
, "\n");
1530 for (m
= option
->num_choices
, choice
= option
->choices
;
1534 _cupsLangPrintf(stdout
, " %s (%s)",
1535 choice
->choice
, choice
->text
);
1537 if (!strcmp(option
->defchoice
, choice
->choice
))
1538 _cupsLangPuts(stdout
, " *\n");
1540 _cupsLangPuts(stdout
, "\n");
1546 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1548 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1549 _cupsLangPrintf(stdout
,
1550 " profiles[%d] = %s/%s %.3f %.3f "
1551 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1552 j
, ppd
->profiles
[j
].resolution
,
1553 ppd
->profiles
[j
].media_type
,
1554 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1555 ppd
->profiles
[j
].matrix
[0][0],
1556 ppd
->profiles
[j
].matrix
[0][1],
1557 ppd
->profiles
[j
].matrix
[0][2],
1558 ppd
->profiles
[j
].matrix
[1][0],
1559 ppd
->profiles
[j
].matrix
[1][1],
1560 ppd
->profiles
[j
].matrix
[1][2],
1561 ppd
->profiles
[j
].matrix
[2][0],
1562 ppd
->profiles
[j
].matrix
[2][1],
1563 ppd
->profiles
[j
].matrix
[2][2]);
1565 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1566 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1567 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1570 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1571 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1572 _cupsLangPrintf(stdout
,
1573 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1574 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1575 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1576 ppd
->attrs
[j
]->text
,
1577 ppd
->attrs
[j
]->value
?
1578 ppd
->attrs
[j
]->value
: "(null)");
1592 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1596 check_basics(const char *filename
) /* I - PPD file to check */
1598 cups_file_t
*fp
; /* File pointer */
1599 int ch
; /* Current character */
1600 int col
, /* Current column */
1601 whitespace
; /* Only seen whitespace? */
1602 int eol
; /* Line endings */
1603 int linenum
; /* Line number */
1604 int mixed
; /* Mixed line endings? */
1607 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1616 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1618 if (ch
== '\r' || ch
== '\n')
1622 if (eol
== EOL_NONE
)
1624 else if (eol
!= EOL_LF
)
1627 else if (ch
== '\r')
1629 if (cupsFilePeekChar(fp
) == '\n')
1631 cupsFileGetChar(fp
);
1633 if (eol
== EOL_NONE
)
1638 else if (eol
== EOL_NONE
)
1644 if (col
> 0 && whitespace
)
1645 _cupsLangPrintf(stdout
,
1646 _(" WARN Line %d only contains whitespace!\n"),
1655 if (ch
!= ' ' && ch
!= '\t')
1663 _cupsLangPuts(stdout
,
1664 _(" WARN File contains a mix of CR, LF, and "
1665 "CR LF line endings!\n"));
1667 if (eol
== EOL_CRLF
)
1668 _cupsLangPuts(stdout
,
1669 _(" WARN Non-Windows PPD files should use lines "
1670 "ending with only LF, not CR LF!\n"));
1677 * 'show_conflicts()' - Show option conflicts in a PPD file.
1681 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
1683 int i
, j
; /* Looping variables */
1684 ppd_const_t
*c
; /* Current constraint */
1685 ppd_option_t
*o1
, *o2
; /* Options */
1686 ppd_choice_t
*c1
, *c2
; /* Choices */
1690 * Loop through all of the UI constraints and report any options
1694 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1697 * Grab pointers to the first option...
1700 o1
= ppdFindOption(ppd
, c
->option1
);
1704 else if (c
->choice1
[0] != '\0')
1707 * This constraint maps to a specific choice.
1710 c1
= ppdFindChoice(o1
, c
->choice1
);
1715 * This constraint applies to any choice for this option.
1718 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
1723 !strcasecmp(c1
->choice
, "None") ||
1724 !strcasecmp(c1
->choice
, "Off") ||
1725 !strcasecmp(c1
->choice
, "False"))
1730 * Grab pointers to the second option...
1733 o2
= ppdFindOption(ppd
, c
->option2
);
1737 else if (c
->choice2
[0] != '\0')
1740 * This constraint maps to a specific choice.
1743 c2
= ppdFindChoice(o2
, c
->choice2
);
1748 * This constraint applies to any choice for this option.
1751 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
1756 !strcasecmp(c2
->choice
, "None") ||
1757 !strcasecmp(c2
->choice
, "Off") ||
1758 !strcasecmp(c2
->choice
, "False"))
1763 * If both options are marked then there is a conflict...
1766 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
1767 _cupsLangPrintf(stdout
,
1768 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
1769 " (constraint=\"%s %s %s %s\")\n"),
1770 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
1771 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1777 * 'usage()' - Show program usage...
1783 _cupsLangPuts(stdout
,
1784 _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] "
1785 "[... filenameN.ppd[.gz]]\n"
1786 " program | cupstestppd [-q] [-r] [-v[v]] -\n"));
1793 * End of "$Id: cupstestppd.c 5926 2006-09-05 20:45:47Z mike $".