2 * "$Id: cupstestppd.c 5549 2006-05-19 19:39:28Z 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" };
117 * Display PPD files for each file listed on the command-line...
120 ppdSetConformance(PPD_CONFORM_STRICT
);
127 for (i
= 1; i
< argc
; i
++)
128 if (argv
[i
][0] == '-' && argv
[i
][1])
130 for (opt
= argv
[i
] + 1; *opt
; opt
++)
133 case 'q' : /* Quiet mode */
136 _cupsLangPuts(stderr
,
137 _("cupstestppd: The -q option is incompatible "
138 "with the -v option.\n"));
145 case 'r' : /* Relaxed mode */
146 ppdSetConformance(PPD_CONFORM_RELAXED
);
149 case 'v' : /* Verbose mode */
152 _cupsLangPuts(stderr
,
153 _("cupstestppd: The -v option is incompatible "
154 "with the -q option.\n"));
169 * Open the PPD file...
172 if (files
&& verbose
>= 0)
173 _cupsLangPuts(stdout
, "\n");
177 if (argv
[i
][0] == '-')
186 ppd
= ppdOpen(stdin
);
191 * Read from a file...
195 printf("%s:", argv
[i
]);
197 ppd
= ppdOpenFile(argv
[i
]);
202 error
= ppdLastError(&line
);
204 if (error
<= PPD_ALLOC_ERROR
)
206 status
= ERROR_FILE_OPEN
;
209 _cupsLangPrintf(stdout
,
211 " **FAIL** Unable to open PPD file - %s\n"),
216 status
= ERROR_PPD_FORMAT
;
220 _cupsLangPrintf(stdout
,
222 " **FAIL** Unable to open PPD file - "
224 ppdErrorString(error
), line
);
228 case PPD_MISSING_PPDADOBE4
:
229 _cupsLangPuts(stdout
,
230 _(" REF: Page 42, section 5.2.\n"));
232 case PPD_MISSING_VALUE
:
233 _cupsLangPuts(stdout
,
234 _(" REF: Page 20, section 3.4.\n"));
236 case PPD_BAD_OPEN_GROUP
:
237 case PPD_NESTED_OPEN_GROUP
:
238 _cupsLangPuts(stdout
,
239 _(" REF: Pages 45-46, section 5.2.\n"));
241 case PPD_BAD_OPEN_UI
:
242 case PPD_NESTED_OPEN_UI
:
243 _cupsLangPuts(stdout
,
244 _(" REF: Pages 42-45, section 5.2.\n"));
246 case PPD_BAD_ORDER_DEPENDENCY
:
247 _cupsLangPuts(stdout
,
248 _(" REF: Pages 48-49, section 5.2.\n"));
250 case PPD_BAD_UI_CONSTRAINTS
:
251 _cupsLangPuts(stdout
,
252 _(" REF: Pages 52-54, section 5.2.\n"));
254 case PPD_MISSING_ASTERISK
:
255 _cupsLangPuts(stdout
,
256 _(" REF: Page 15, section 3.2.\n"));
258 case PPD_LINE_TOO_LONG
:
259 _cupsLangPuts(stdout
,
260 _(" REF: Page 15, section 3.1.\n"));
262 case PPD_ILLEGAL_CHARACTER
:
263 _cupsLangPuts(stdout
,
264 _(" REF: Page 15, section 3.1.\n"));
266 case PPD_ILLEGAL_MAIN_KEYWORD
:
267 _cupsLangPuts(stdout
,
268 _(" REF: Pages 16-17, section 3.2.\n"));
270 case PPD_ILLEGAL_OPTION_KEYWORD
:
271 _cupsLangPuts(stdout
,
272 _(" REF: Page 19, section 3.3.\n"));
274 case PPD_ILLEGAL_TRANSLATION
:
275 _cupsLangPuts(stdout
,
276 _(" REF: Page 27, section 3.5.\n"));
282 check_basics(argv
[i
]);
290 * Show the header and then perform basic conformance tests (limited
291 * only by what the CUPS PPD functions actually load...)
298 _cupsLangPuts(stdout
,
299 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
301 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
303 ppdversion
= (int)(10 * atof(attr
->value
) + 0.5);
306 * Look for default keywords with no matching option...
309 for (i
= 0; i
< ppd
->num_attrs
; i
++)
311 attr
= ppd
->attrs
[i
];
313 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
314 !strcmp(attr
->name
, "DefaultFont") ||
315 !strcmp(attr
->name
, "DefaultImageableArea") ||
316 !strcmp(attr
->name
, "DefaultOutputOrder") ||
317 !strcmp(attr
->name
, "DefaultPaperDimension") ||
318 !strcmp(attr
->name
, "DefaultTransfer"))
321 if (!strncmp(attr
->name
, "Default", 7))
323 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
324 strcmp(attr
->value
, "Unknown"))
327 * Check that the default option value matches a choice...
330 for (j
= 0; j
< option
->num_choices
; j
++)
331 if (!strcmp(option
->choices
[j
].choice
, attr
->value
))
334 if (j
>= option
->num_choices
)
338 if (!errors
&& !verbose
)
339 _cupsLangPuts(stdout
, _(" FAIL\n"));
341 _cupsLangPrintf(stdout
,
342 _(" **FAIL** %s %s does not exist!\n"),
343 attr
->name
, attr
->value
);
352 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
356 if (!errors
&& !verbose
)
357 _cupsLangPuts(stdout
, _(" FAIL\n"));
359 _cupsLangPuts(stdout
,
360 _(" **FAIL** REQUIRED DefaultImageableArea\n"
361 " REF: Page 102, section 5.15.\n"));
366 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
367 strcmp(attr
->value
, "Unknown"))
371 if (!errors
&& !verbose
)
372 _cupsLangPuts(stdout
, _(" FAIL\n"));
374 _cupsLangPrintf(stdout
,
375 _(" **FAIL** BAD DefaultImageableArea %s!\n"
376 " REF: Page 102, section 5.15.\n"),
385 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
388 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
392 if (!errors
&& !verbose
)
393 _cupsLangPuts(stdout
, _(" FAIL\n"));
395 _cupsLangPuts(stdout
,
396 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
397 " REF: Page 103, section 5.15.\n"));
402 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
403 strcmp(attr
->value
, "Unknown"))
407 if (!errors
&& !verbose
)
408 _cupsLangPuts(stdout
, _(" FAIL\n"));
410 _cupsLangPrintf(stdout
,
411 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
412 " REF: Page 103, section 5.15.\n"),
418 else if (verbose
> 0)
419 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
421 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
422 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
425 * Verify that we have a default choice...
428 if (option
->defchoice
[0])
430 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
431 strcmp(option
->defchoice
, "Unknown"))
435 if (!errors
&& !verbose
)
436 _cupsLangPuts(stdout
, _(" FAIL\n"));
438 _cupsLangPrintf(stdout
,
439 _(" **FAIL** BAD Default%s %s\n"
440 " REF: Page 40, section 4.5.\n"),
441 option
->keyword
, option
->defchoice
);
446 else if (verbose
> 0)
447 _cupsLangPrintf(stdout
,
448 _(" PASS Default%s\n"),
455 if (!errors
&& !verbose
)
456 _cupsLangPuts(stdout
, _(" FAIL\n"));
458 _cupsLangPrintf(stdout
,
459 _(" **FAIL** REQUIRED Default%s\n"
460 " REF: Page 40, section 4.5.\n"),
468 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
471 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
477 if (!errors
&& !verbose
)
478 _cupsLangPuts(stdout
, _(" FAIL\n"));
480 _cupsLangPuts(stdout
,
481 _(" **FAIL** REQUIRED FileVersion\n"
482 " REF: Page 56, section 5.3.\n"));
488 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
491 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
497 if (!errors
&& !verbose
)
498 _cupsLangPuts(stdout
, _(" FAIL\n"));
500 _cupsLangPuts(stdout
,
501 _(" **FAIL** REQUIRED FormatVersion\n"
502 " REF: Page 56, section 5.3.\n"));
508 if (ppd
->lang_encoding
!= NULL
)
511 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
513 else if (ppdversion
> 40)
517 if (!errors
&& !verbose
)
518 _cupsLangPuts(stdout
, _(" FAIL\n"));
520 _cupsLangPuts(stdout
,
521 _(" **FAIL** REQUIRED LanguageEncoding\n"
522 " REF: Pages 56-57, section 5.3.\n"));
528 if (ppd
->lang_version
!= NULL
)
531 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
537 if (!errors
&& !verbose
)
538 _cupsLangPuts(stdout
, _(" FAIL\n"));
540 _cupsLangPuts(stdout
,
541 _(" **FAIL** REQUIRED LanguageVersion\n"
542 " REF: Pages 57-58, section 5.3.\n"));
548 if (ppd
->manufacturer
!= NULL
)
550 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
551 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
555 if (!errors
&& !verbose
)
556 _cupsLangPuts(stdout
, _(" FAIL\n"));
558 _cupsLangPuts(stdout
,
559 _(" **FAIL** BAD Manufacturer (should be "
561 " REF: Page 211, table D.1.\n"));
566 else if (verbose
> 0)
567 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
569 else if (ppdversion
>= 43)
573 if (!errors
&& !verbose
)
574 _cupsLangPuts(stdout
, _(" FAIL\n"));
576 _cupsLangPuts(stdout
,
577 _(" **FAIL** REQUIRED Manufacturer\n"
578 " REF: Pages 58-59, section 5.3.\n"));
584 if (ppd
->modelname
!= NULL
)
586 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
587 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
594 if (!errors
&& !verbose
)
595 _cupsLangPuts(stdout
, _(" FAIL\n"));
597 _cupsLangPrintf(stdout
,
598 _(" **FAIL** BAD ModelName - \"%c\" not "
599 "allowed in string.\n"
600 " REF: Pages 59-60, section 5.3.\n"),
606 else if (verbose
> 0)
607 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
613 if (!errors
&& !verbose
)
614 _cupsLangPuts(stdout
, _(" FAIL\n"));
616 _cupsLangPuts(stdout
,
617 _(" **FAIL** REQUIRED ModelName\n"
618 " REF: Pages 59-60, section 5.3.\n"));
624 if (ppd
->nickname
!= NULL
)
627 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
633 if (!errors
&& !verbose
)
634 _cupsLangPuts(stdout
, _(" FAIL\n"));
636 _cupsLangPuts(stdout
,
637 _(" **FAIL** REQUIRED NickName\n"
638 " REF: Page 60, section 5.3.\n"));
644 if (ppdFindOption(ppd
, "PageSize") != NULL
)
647 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
653 if (!errors
&& !verbose
)
654 _cupsLangPuts(stdout
, _(" FAIL\n"));
656 _cupsLangPuts(stdout
,
657 _(" **FAIL** REQUIRED PageSize\n"
658 " REF: Pages 99-100, section 5.14.\n"));
664 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
667 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
673 if (!errors
&& !verbose
)
674 _cupsLangPuts(stdout
, _(" FAIL\n"));
676 _cupsLangPuts(stdout
,
677 _(" **FAIL** REQUIRED PageRegion\n"
678 " REF: Page 100, section 5.14.\n"));
684 if (ppd
->pcfilename
!= NULL
)
687 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
693 if (!errors
&& !verbose
)
694 _cupsLangPuts(stdout
, _(" FAIL\n"));
696 _cupsLangPuts(stdout
,
697 _(" **FAIL** REQUIRED PCFileName\n"
698 " REF: Pages 61-62, section 5.3.\n"));
704 if (ppd
->product
!= NULL
)
706 if (ppd
->product
[0] != '(' ||
707 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
711 if (!errors
&& !verbose
)
712 _cupsLangPuts(stdout
, _(" FAIL\n"));
714 _cupsLangPuts(stdout
,
715 _(" **FAIL** BAD Product - not \"(string)\".\n"
716 " REF: Page 62, section 5.3.\n"));
721 else if (verbose
> 0)
722 _cupsLangPuts(stdout
, _(" PASS Product\n"));
728 if (!errors
&& !verbose
)
729 _cupsLangPuts(stdout
, _(" FAIL\n"));
731 _cupsLangPuts(stdout
,
732 _(" **FAIL** REQUIRED Product\n"
733 " REF: Page 62, section 5.3.\n"));
739 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
742 char junkstr
[255]; /* Temp string */
743 int junkint
; /* Temp integer */
746 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
750 if (!errors
&& !verbose
)
751 _cupsLangPuts(stdout
, _(" FAIL\n"));
753 _cupsLangPuts(stdout
,
754 _(" **FAIL** BAD PSVersion - not \"(string) "
756 " REF: Pages 62-64, section 5.3.\n"));
761 else if (verbose
> 0)
762 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
768 if (!errors
&& !verbose
)
769 _cupsLangPuts(stdout
, _(" FAIL\n"));
771 _cupsLangPuts(stdout
,
772 _(" **FAIL** REQUIRED PSVersion\n"
773 " REF: Pages 62-64, section 5.3.\n"));
779 if (ppd
->shortnickname
!= NULL
)
781 if (strlen(ppd
->shortnickname
) > 31)
785 if (!errors
&& !verbose
)
786 _cupsLangPuts(stdout
, _(" FAIL\n"));
788 _cupsLangPuts(stdout
,
789 _(" **FAIL** BAD ShortNickName - longer "
791 " REF: Pages 64-65, section 5.3.\n"));
796 else if (verbose
> 0)
797 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
799 else if (ppdversion
>= 43)
803 if (!errors
&& !verbose
)
804 _cupsLangPuts(stdout
, _(" FAIL\n"));
806 _cupsLangPuts(stdout
,
807 _(" **FAIL** REQUIRED ShortNickName\n"
808 " REF: Page 64-65, section 5.3.\n"));
814 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
815 strstr(ppd
->patches
, "*End"))
819 if (!errors
&& !verbose
)
820 _cupsLangPuts(stdout
, _(" FAIL\n"));
822 _cupsLangPuts(stdout
,
823 _(" **FAIL** BAD JobPatchFile attribute in file\n"
824 " REF: Page 24, section 3.4.\n"));
831 * Check for page sizes without the corresponding ImageableArea or
832 * PaperDimension values...
835 if (ppd
->num_sizes
== 0)
839 if (!errors
&& !verbose
)
840 _cupsLangPuts(stdout
, _(" FAIL\n"));
842 _cupsLangPuts(stdout
,
843 _(" **FAIL** REQUIRED PageSize\n"
844 " REF: Page 41, section 5.\n"
845 " REF: Page 99, section 5.14.\n"));
852 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
855 * Don't check custom size...
858 if (!strcmp(size
->name
, "Custom"))
862 * Check for ImageableArea...
865 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
866 size
->right
== 0.0 && size
->top
== 0.0)
870 if (!errors
&& !verbose
)
871 _cupsLangPuts(stdout
, _(" FAIL\n"));
873 _cupsLangPrintf(stdout
,
874 _(" **FAIL** REQUIRED ImageableArea for "
876 " REF: Page 41, section 5.\n"
877 " REF: Page 102, section 5.15.\n"),
885 * Check for PaperDimension...
888 if (size
->width
== 0.0 && size
->length
== 0.0)
892 if (!errors
&& !verbose
)
893 _cupsLangPuts(stdout
, _(" FAIL\n"));
895 _cupsLangPrintf(stdout
,
896 _(" **FAIL** REQUIRED PaperDimension "
898 " REF: Page 41, section 5.\n"
899 " REF: Page 103, section 5.15.\n"),
909 * Check for valid Resolution, JCLResolution, or SetResolution values...
912 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
913 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
914 option
= ppdFindOption(ppd
, "SetResolution");
918 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
921 * Verify that all resolution options are of the form NNNdpi
925 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
926 if (ptr
> choice
->choice
&& xdpi
> 0)
929 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
936 if (xdpi
<= 0 || ydpi
<= 0 || strcmp(ptr
, "dpi"))
940 if (!errors
&& !verbose
)
941 _cupsLangPuts(stdout
, _(" FAIL\n"));
943 _cupsLangPrintf(stdout
,
944 _(" **FAIL** Bad %s choice %s!\n"
945 " REF: Page 84, section 5.9\n"),
946 option
->keyword
, choice
->choice
);
955 * Check for a duplex option, and for standard values...
958 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
959 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
960 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
961 option
= ppdFindOption(ppd
, "KD03Duplex");
965 if (ppdFindChoice(option
, "None") == NULL
)
969 if (!errors
&& !verbose
)
970 _cupsLangPuts(stdout
, _(" FAIL\n"));
972 _cupsLangPrintf(stdout
,
973 _(" **FAIL** REQUIRED %s does not define "
975 " REF: Page 122, section 5.17\n"),
982 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
983 if (strcmp(choice
->choice
, "None") &&
984 strcmp(choice
->choice
, "DuplexNoTumble") &&
985 strcmp(choice
->choice
, "DuplexTumble") &&
986 strcmp(choice
->choice
, "SimplexTumble"))
990 if (!errors
&& !verbose
)
991 _cupsLangPuts(stdout
, _(" FAIL\n"));
993 _cupsLangPrintf(stdout
,
994 _(" **FAIL** Bad %s choice %s!\n"
995 " REF: Page 122, section 5.17\n"),
996 option
->keyword
, choice
->choice
);
1003 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1007 * This file contains localizations, check them...
1010 char *languages
, /* Copy of attribute value */
1011 *langstart
, /* Start of current language */
1012 *langptr
, /* Pointer into languages */
1013 keyword
[PPD_MAX_NAME
]; /* Localization keyword */
1016 languages
= strdup(attr
->value
);
1017 for (langptr
= languages
; *langptr
;)
1020 * Skip leading whitespace...
1023 while (isspace(*langptr
& 255))
1030 * Find the end of this language name...
1033 for (langstart
= langptr
;
1034 *langptr
&& !isspace(*langptr
& 255);
1040 j
= strlen(langstart
);
1041 if (j
!= 2 && j
!= 5)
1045 if (!errors
&& !verbose
)
1046 _cupsLangPuts(stdout
, _(" FAIL\n"));
1048 _cupsLangPrintf(stdout
,
1049 _(" **FAIL** Bad language \"%s\"!\n"),
1058 * Loop through all options and choices...
1061 for (option
= ppdFirstOption(ppd
);
1063 option
= ppdNextOption(ppd
))
1065 snprintf(keyword
, sizeof(keyword
), "%s.Translation", langstart
);
1066 if (!ppdFindAttr(ppd
, keyword
, option
->keyword
))
1070 if (!errors
&& !verbose
)
1071 _cupsLangPuts(stdout
, _(" FAIL\n"));
1073 _cupsLangPrintf(stdout
,
1074 _(" **FAIL** Missing \"%s\" translation "
1075 "string for option %s!\n"),
1076 langstart
, option
->keyword
);
1082 for (ptr
= option
->text
; *ptr
; ptr
++)
1090 if (!errors
&& !verbose
)
1091 _cupsLangPuts(stdout
, _(" FAIL\n"));
1093 _cupsLangPrintf(stdout
,
1094 _(" **FAIL** Default translation "
1095 "string for option %s contains 8-bit "
1103 snprintf(keyword
, sizeof(keyword
), "%s.%s", langstart
,
1105 for (j
= 0; j
< option
->num_choices
; j
++)
1107 if (!ppdFindAttr(ppd
, keyword
, option
->choices
[j
].choice
))
1111 if (!errors
&& !verbose
)
1112 _cupsLangPuts(stdout
, _(" FAIL\n"));
1114 _cupsLangPrintf(stdout
,
1115 _(" **FAIL** Missing \"%s\" "
1116 "translation string for option %s, "
1118 langstart
, option
->keyword
,
1119 option
->choices
[j
].choice
);
1125 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1133 if (!errors
&& !verbose
)
1134 _cupsLangPuts(stdout
, _(" FAIL\n"));
1136 _cupsLangPrintf(stdout
,
1137 _(" **FAIL** Default translation "
1138 "string for option %s choice %s contains "
1139 "8-bit characters!\n"),
1141 option
->choices
[j
].choice
);
1151 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
1153 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
1155 char super
[16], /* Filter super type */
1156 type
[256], /* Filter type */
1157 program
[256]; /* Filter program */
1158 int cost
; /* Filter cost */
1162 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1167 if (!errors
&& !verbose
)
1168 _cupsLangPuts(stdout
, _(" FAIL\n"));
1170 _cupsLangPrintf(stdout
,
1171 _(" **FAIL** Bad cupsFilter value \"%s\"!\n"),
1172 attr
->value
? attr
->value
: "");
1179 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1180 strcmp(attr
->name
, "1284DeviceID"))
1184 if (!errors
&& !verbose
)
1185 _cupsLangPuts(stdout
, _(" FAIL\n"));
1187 _cupsLangPuts(stdout
,
1188 _(" **FAIL** 1284DeviceId must be 1284DeviceID!\n"
1189 " REF: Page 72, section 5.5\n"));
1196 status
= ERROR_CONFORMANCE
;
1198 _cupsLangPuts(stdout
, _(" PASS\n"));
1202 check_basics(argv
[i
]);
1205 * Look for default keywords with no corresponding option...
1208 for (i
= 0; i
< ppd
->num_attrs
; i
++)
1210 attr
= ppd
->attrs
[i
];
1212 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1213 !strcmp(attr
->name
, "DefaultColorSep") ||
1214 !strcmp(attr
->name
, "DefaultFont") ||
1215 !strcmp(attr
->name
, "DefaultImageableArea") ||
1216 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1217 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1218 !strcmp(attr
->name
, "DefaultScreenProc") ||
1219 !strcmp(attr
->name
, "DefaultTransfer"))
1222 if (!strncmp(attr
->name
, "Default", 7) &&
1223 !ppdFindOption(ppd
, attr
->name
+ 7))
1224 _cupsLangPrintf(stdout
,
1225 _(" WARN %s has no corresponding "
1231 * Check for old Duplex option names...
1234 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1235 option
= ppdFindOption(ppd
, "KD03Duplex");
1239 _cupsLangPrintf(stdout
,
1240 _(" WARN Duplex option keyword %s "
1241 "should be named Duplex or JCLDuplex!\n"
1242 " REF: Page 122, section 5.17\n"),
1246 ppdMarkDefaults(ppd
);
1247 if (ppdConflicts(ppd
))
1249 _cupsLangPuts(stdout
,
1250 _(" WARN Default choices conflicting!\n"));
1252 show_conflicts(ppd
);
1255 if (ppdversion
< 43)
1257 _cupsLangPrintf(stdout
,
1258 _(" WARN Obsolete PPD version %.1f!\n"
1259 " REF: Page 42, section 5.2.\n"),
1263 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1265 _cupsLangPuts(stdout
,
1266 _(" WARN LanguageEncoding required by PPD "
1268 " REF: Pages 56-57, section 5.3.\n"));
1271 if (!ppd
->manufacturer
&& ppdversion
< 43)
1273 _cupsLangPuts(stdout
,
1274 _(" WARN Manufacturer required by PPD "
1276 " REF: Pages 58-59, section 5.3.\n"));
1280 * Treat a PCFileName attribute longer than 12 characters as
1281 * a warning and not a hard error...
1284 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1286 _cupsLangPuts(stdout
,
1287 _(" WARN PCFileName longer than 8.3 in "
1288 "violation of PPD spec.\n"
1289 " REF: Pages 61-62, section 5.3.\n"));
1292 if (!ppd
->shortnickname
&& ppdversion
< 43)
1294 _cupsLangPuts(stdout
,
1295 _(" WARN ShortNickName required by PPD "
1297 " REF: Pages 64-65, section 5.3.\n"));
1301 * Check the Protocols line and flag PJL + BCP since TBCP is
1302 * usually used with PJL...
1307 if (strstr(ppd
->protocols
, "PJL") &&
1308 strstr(ppd
->protocols
, "BCP") &&
1309 !strstr(ppd
->protocols
, "TBCP"))
1311 _cupsLangPuts(stdout
,
1312 _(" WARN Protocols contains both PJL "
1313 "and BCP; expected TBCP.\n"
1314 " REF: Pages 78-79, section 5.7.\n"));
1317 if (strstr(ppd
->protocols
, "PJL") &&
1318 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1320 _cupsLangPuts(stdout
,
1321 _(" WARN Protocols contains PJL but JCL "
1322 "attributes are not set.\n"
1323 " REF: Pages 78-79, section 5.7.\n"));
1328 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1329 * which are errors according to the spec but won't cause problems
1330 * with CUPS specifically...
1333 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1334 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1336 len
= strlen(option
->keyword
);
1338 for (m
= 0, group2
= ppd
->groups
;
1339 m
< ppd
->num_groups
;
1341 for (n
= 0, option2
= group2
->options
;
1342 n
< group2
->num_options
;
1344 if (option
!= option2
&&
1345 len
< strlen(option2
->keyword
) &&
1346 !strncmp(option
->keyword
, option2
->keyword
, len
))
1348 _cupsLangPrintf(stdout
,
1349 _(" WARN %s shares a common "
1351 " REF: Page 15, section "
1353 option
->keyword
, option2
->keyword
);
1361 _cupsLangPrintf(stdout
, _(" %d ERROR%s FOUND\n"),
1362 errors
, errors
== 1 ? "" : "S");
1364 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1368 * Then list the options, if "-v" was provided...
1373 _cupsLangPrintf(stdout
,
1375 " language_level = %d\n"
1376 " color_device = %s\n"
1377 " variable_sizes = %s\n"
1378 " landscape = %d\n",
1379 ppd
->language_level
,
1380 ppd
->color_device
? "TRUE" : "FALSE",
1381 ppd
->variable_sizes
? "TRUE" : "FALSE",
1384 switch (ppd
->colorspace
)
1387 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1390 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1393 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1396 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1399 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1403 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1404 ppd
->num_emulations
);
1405 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1406 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1407 j
, ppd
->emulations
[j
].name
);
1409 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1410 ppd
->lang_encoding
);
1411 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1413 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1414 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1415 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1416 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1418 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1419 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1420 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1421 ppd
->shortnickname
);
1422 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1423 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1425 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1426 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1428 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1431 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1433 _cupsLangPrintf(stdout
,
1434 " options[%d] = %s (%s) %s %s %.0f "
1436 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1437 sections
[option
->section
], option
->order
,
1438 option
->num_choices
);
1440 if (!strcmp(option
->keyword
, "PageSize") ||
1441 !strcmp(option
->keyword
, "PageRegion"))
1443 for (m
= option
->num_choices
, choice
= option
->choices
;
1447 size
= ppdPageSize(ppd
, choice
->choice
);
1450 _cupsLangPrintf(stdout
,
1452 choice
->choice
, choice
->text
);
1454 _cupsLangPrintf(stdout
,
1455 " %s (%s) = %.2fx%.2fin "
1456 "(%.1f,%.1f,%.1f,%.1f)",
1457 choice
->choice
, choice
->text
,
1458 size
->width
/ 72.0, size
->length
/ 72.0,
1459 size
->left
/ 72.0, size
->bottom
/ 72.0,
1460 size
->right
/ 72.0, size
->top
/ 72.0);
1462 if (!strcmp(option
->defchoice
, choice
->choice
))
1463 _cupsLangPuts(stdout
, " *\n");
1465 _cupsLangPuts(stdout
, "\n");
1470 for (m
= option
->num_choices
, choice
= option
->choices
;
1474 _cupsLangPrintf(stdout
, " %s (%s)",
1475 choice
->choice
, choice
->text
);
1477 if (!strcmp(option
->defchoice
, choice
->choice
))
1478 _cupsLangPuts(stdout
, " *\n");
1480 _cupsLangPuts(stdout
, "\n");
1486 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1488 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1489 _cupsLangPrintf(stdout
,
1490 " profiles[%d] = %s/%s %.3f %.3f "
1491 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1492 j
, ppd
->profiles
[j
].resolution
,
1493 ppd
->profiles
[j
].media_type
,
1494 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1495 ppd
->profiles
[j
].matrix
[0][0],
1496 ppd
->profiles
[j
].matrix
[0][1],
1497 ppd
->profiles
[j
].matrix
[0][2],
1498 ppd
->profiles
[j
].matrix
[1][0],
1499 ppd
->profiles
[j
].matrix
[1][1],
1500 ppd
->profiles
[j
].matrix
[1][2],
1501 ppd
->profiles
[j
].matrix
[2][0],
1502 ppd
->profiles
[j
].matrix
[2][1],
1503 ppd
->profiles
[j
].matrix
[2][2]);
1505 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1506 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1507 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1510 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1511 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1512 _cupsLangPrintf(stdout
,
1513 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1514 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1515 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1516 ppd
->attrs
[j
]->text
,
1517 ppd
->attrs
[j
]->value
?
1518 ppd
->attrs
[j
]->value
: "(null)");
1532 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1536 check_basics(const char *filename
) /* I - PPD file to check */
1538 cups_file_t
*fp
; /* File pointer */
1539 int ch
; /* Current character */
1540 int col
, /* Current column */
1541 whitespace
; /* Only seen whitespace? */
1542 int eol
; /* Line endings */
1543 int linenum
; /* Line number */
1544 int mixed
; /* Mixed line endings? */
1547 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1556 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1558 if (ch
== '\r' || ch
== '\n')
1562 if (eol
== EOL_NONE
)
1564 else if (eol
!= EOL_LF
)
1567 else if (ch
== '\r')
1569 if (cupsFilePeekChar(fp
) == '\n')
1571 cupsFileGetChar(fp
);
1573 if (eol
== EOL_NONE
)
1578 else if (eol
== EOL_NONE
)
1584 if (col
> 0 && whitespace
)
1585 _cupsLangPrintf(stdout
,
1586 _(" WARN Line %d only contains whitespace!\n"),
1595 if (ch
!= ' ' && ch
!= '\t')
1603 _cupsLangPuts(stdout
,
1604 _(" WARN File contains a mix of CR, LF, and "
1605 "CR LF line endings!\n"));
1607 if (eol
== EOL_CRLF
)
1608 _cupsLangPuts(stdout
,
1609 _(" WARN Non-Windows PPD files should use lines "
1610 "ending with only LF, not CR LF!\n"));
1617 * 'show_conflicts()' - Show option conflicts in a PPD file.
1621 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
1623 int i
, j
; /* Looping variables */
1624 ppd_const_t
*c
; /* Current constraint */
1625 ppd_option_t
*o1
, *o2
; /* Options */
1626 ppd_choice_t
*c1
, *c2
; /* Choices */
1630 * Loop through all of the UI constraints and report any options
1634 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1637 * Grab pointers to the first option...
1640 o1
= ppdFindOption(ppd
, c
->option1
);
1644 else if (c
->choice1
[0] != '\0')
1647 * This constraint maps to a specific choice.
1650 c1
= ppdFindChoice(o1
, c
->choice1
);
1655 * This constraint applies to any choice for this option.
1658 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
1663 !strcasecmp(c1
->choice
, "None") ||
1664 !strcasecmp(c1
->choice
, "Off") ||
1665 !strcasecmp(c1
->choice
, "False"))
1670 * Grab pointers to the second option...
1673 o2
= ppdFindOption(ppd
, c
->option2
);
1677 else if (c
->choice2
[0] != '\0')
1680 * This constraint maps to a specific choice.
1683 c2
= ppdFindChoice(o2
, c
->choice2
);
1688 * This constraint applies to any choice for this option.
1691 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
1696 !strcasecmp(c2
->choice
, "None") ||
1697 !strcasecmp(c2
->choice
, "Off") ||
1698 !strcasecmp(c2
->choice
, "False"))
1703 * If both options are marked then there is a conflict...
1706 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
1707 _cupsLangPrintf(stdout
,
1708 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
1709 " (constraint=\"%s %s %s %s\")\n"),
1710 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
1711 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1717 * 'usage()' - Show program usage...
1723 _cupsLangPuts(stdout
,
1724 _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] "
1725 "[... filenameN.ppd[.gz]]\n"
1726 " program | cupstestppd [-q] [-r] [-v[v]] -\n"));
1733 * End of "$Id: cupstestppd.c 5549 2006-05-19 19:39:28Z mike $".