2 * "$Id: cupstestppd.c 6430 2007-04-02 14:01:55Z mike $"
4 * PPD test program for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2007 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...
33 * valid_utf8() - Check whether a string contains valid UTF-8 text.
37 * Include necessary headers...
40 #include <cups/string.h>
41 #include <cups/cups.h>
42 #include <cups/i18n.h>
78 void check_basics(const char *filename
);
79 void show_conflicts(ppd_file_t
*ppd
);
81 int valid_utf8(const char *s
);
84 * 'main()' - Main entry for test program.
87 int /* O - Exit status */
88 main(int argc
, /* I - Number of command-line arguments */
89 char *argv
[]) /* I - Command-line arguments */
91 int i
, j
, k
, m
, n
; /* Looping vars */
92 int len
; /* Length of option name */
93 char *opt
; /* Option character */
94 const char *ptr
; /* Pointer into string */
95 int files
; /* Number of files */
96 int verbose
; /* Want verbose output? */
97 int status
; /* Exit status */
98 int errors
; /* Number of conformance errors */
99 int ppdversion
; /* PPD spec version in PPD file */
100 ppd_status_t error
; /* Status of ppdOpen*() */
101 int line
; /* Line number for error */
102 int xdpi
, /* X resolution */
103 ydpi
; /* Y resolution */
104 ppd_file_t
*ppd
; /* PPD file record */
105 ppd_attr_t
*attr
; /* PPD attribute */
106 ppd_size_t
*size
; /* Size record */
107 ppd_group_t
*group
; /* UI group */
108 ppd_option_t
*option
; /* Standard UI option */
109 ppd_group_t
*group2
; /* UI group */
110 ppd_option_t
*option2
; /* Standard UI option */
111 ppd_choice_t
*choice
; /* Standard UI option choice */
112 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
113 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
114 "JCL", "PAGE", "PROLOG" };
117 _cupsSetLocale(argv
);
120 * Display PPD files for each file listed on the command-line...
123 ppdSetConformance(PPD_CONFORM_STRICT
);
130 for (i
= 1; i
< argc
; i
++)
131 if (argv
[i
][0] == '-' && argv
[i
][1])
133 for (opt
= argv
[i
] + 1; *opt
; opt
++)
136 case 'q' : /* Quiet mode */
139 _cupsLangPuts(stderr
,
140 _("cupstestppd: The -q option is incompatible "
141 "with the -v option.\n"));
148 case 'r' : /* Relaxed mode */
149 ppdSetConformance(PPD_CONFORM_RELAXED
);
152 case 'v' : /* Verbose mode */
155 _cupsLangPuts(stderr
,
156 _("cupstestppd: The -v option is incompatible "
157 "with the -q option.\n"));
172 * Open the PPD file...
175 if (files
&& verbose
>= 0)
176 _cupsLangPuts(stdout
, "\n");
180 if (argv
[i
][0] == '-')
189 ppd
= ppdOpen(stdin
);
194 * Read from a file...
198 printf("%s:", argv
[i
]);
200 ppd
= ppdOpenFile(argv
[i
]);
205 error
= ppdLastError(&line
);
207 if (error
<= PPD_ALLOC_ERROR
)
209 status
= ERROR_FILE_OPEN
;
212 _cupsLangPrintf(stdout
,
214 " **FAIL** Unable to open PPD file - %s\n"),
219 status
= ERROR_PPD_FORMAT
;
223 _cupsLangPrintf(stdout
,
225 " **FAIL** Unable to open PPD file - "
227 ppdErrorString(error
), line
);
231 case PPD_MISSING_PPDADOBE4
:
232 _cupsLangPuts(stdout
,
233 _(" REF: Page 42, section 5.2.\n"));
235 case PPD_MISSING_VALUE
:
236 _cupsLangPuts(stdout
,
237 _(" REF: Page 20, section 3.4.\n"));
239 case PPD_BAD_OPEN_GROUP
:
240 case PPD_NESTED_OPEN_GROUP
:
241 _cupsLangPuts(stdout
,
242 _(" REF: Pages 45-46, section 5.2.\n"));
244 case PPD_BAD_OPEN_UI
:
245 case PPD_NESTED_OPEN_UI
:
246 _cupsLangPuts(stdout
,
247 _(" REF: Pages 42-45, section 5.2.\n"));
249 case PPD_BAD_ORDER_DEPENDENCY
:
250 _cupsLangPuts(stdout
,
251 _(" REF: Pages 48-49, section 5.2.\n"));
253 case PPD_BAD_UI_CONSTRAINTS
:
254 _cupsLangPuts(stdout
,
255 _(" REF: Pages 52-54, section 5.2.\n"));
257 case PPD_MISSING_ASTERISK
:
258 _cupsLangPuts(stdout
,
259 _(" REF: Page 15, section 3.2.\n"));
261 case PPD_LINE_TOO_LONG
:
262 _cupsLangPuts(stdout
,
263 _(" REF: Page 15, section 3.1.\n"));
265 case PPD_ILLEGAL_CHARACTER
:
266 _cupsLangPuts(stdout
,
267 _(" REF: Page 15, section 3.1.\n"));
269 case PPD_ILLEGAL_MAIN_KEYWORD
:
270 _cupsLangPuts(stdout
,
271 _(" REF: Pages 16-17, section 3.2.\n"));
273 case PPD_ILLEGAL_OPTION_KEYWORD
:
274 _cupsLangPuts(stdout
,
275 _(" REF: Page 19, section 3.3.\n"));
277 case PPD_ILLEGAL_TRANSLATION
:
278 _cupsLangPuts(stdout
,
279 _(" REF: Page 27, section 3.5.\n"));
285 check_basics(argv
[i
]);
293 * Show the header and then perform basic conformance tests (limited
294 * only by what the CUPS PPD functions actually load...)
301 _cupsLangPuts(stdout
,
302 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
304 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
306 ppdversion
= (int)(10 * atof(attr
->value
) + 0.5);
309 * Look for default keywords with no matching option...
312 for (j
= 0; j
< ppd
->num_attrs
; j
++)
314 attr
= ppd
->attrs
[j
];
316 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
317 !strcmp(attr
->name
, "DefaultFont") ||
318 !strcmp(attr
->name
, "DefaultImageableArea") ||
319 !strcmp(attr
->name
, "DefaultOutputOrder") ||
320 !strcmp(attr
->name
, "DefaultPaperDimension") ||
321 !strcmp(attr
->name
, "DefaultTransfer"))
324 if (!strncmp(attr
->name
, "Default", 7))
326 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
327 strcmp(attr
->value
, "Unknown"))
330 * Check that the default option value matches a choice...
333 for (k
= 0; k
< option
->num_choices
; k
++)
334 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
337 if (k
>= option
->num_choices
)
341 if (!errors
&& !verbose
)
342 _cupsLangPuts(stdout
, _(" FAIL\n"));
344 _cupsLangPrintf(stdout
,
345 _(" **FAIL** %s %s does not exist!\n"),
346 attr
->name
, attr
->value
);
355 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
359 if (!errors
&& !verbose
)
360 _cupsLangPuts(stdout
, _(" FAIL\n"));
362 _cupsLangPuts(stdout
,
363 _(" **FAIL** REQUIRED DefaultImageableArea\n"
364 " REF: Page 102, section 5.15.\n"));
369 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
370 strcmp(attr
->value
, "Unknown"))
374 if (!errors
&& !verbose
)
375 _cupsLangPuts(stdout
, _(" FAIL\n"));
377 _cupsLangPrintf(stdout
,
378 _(" **FAIL** BAD DefaultImageableArea %s!\n"
379 " REF: Page 102, section 5.15.\n"),
388 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
391 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
395 if (!errors
&& !verbose
)
396 _cupsLangPuts(stdout
, _(" FAIL\n"));
398 _cupsLangPuts(stdout
,
399 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
400 " REF: Page 103, section 5.15.\n"));
405 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
406 strcmp(attr
->value
, "Unknown"))
410 if (!errors
&& !verbose
)
411 _cupsLangPuts(stdout
, _(" FAIL\n"));
413 _cupsLangPrintf(stdout
,
414 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
415 " REF: Page 103, section 5.15.\n"),
421 else if (verbose
> 0)
422 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
424 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
425 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
428 * Verify that we have a default choice...
431 if (option
->defchoice
[0])
433 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
434 strcmp(option
->defchoice
, "Unknown"))
438 if (!errors
&& !verbose
)
439 _cupsLangPuts(stdout
, _(" FAIL\n"));
441 _cupsLangPrintf(stdout
,
442 _(" **FAIL** BAD Default%s %s\n"
443 " REF: Page 40, section 4.5.\n"),
444 option
->keyword
, option
->defchoice
);
449 else if (verbose
> 0)
450 _cupsLangPrintf(stdout
,
451 _(" PASS Default%s\n"),
458 if (!errors
&& !verbose
)
459 _cupsLangPuts(stdout
, _(" FAIL\n"));
461 _cupsLangPrintf(stdout
,
462 _(" **FAIL** REQUIRED Default%s\n"
463 " REF: Page 40, section 4.5.\n"),
471 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
474 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
480 if (!errors
&& !verbose
)
481 _cupsLangPuts(stdout
, _(" FAIL\n"));
483 _cupsLangPuts(stdout
,
484 _(" **FAIL** REQUIRED FileVersion\n"
485 " REF: Page 56, section 5.3.\n"));
491 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
494 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
500 if (!errors
&& !verbose
)
501 _cupsLangPuts(stdout
, _(" FAIL\n"));
503 _cupsLangPuts(stdout
,
504 _(" **FAIL** REQUIRED FormatVersion\n"
505 " REF: Page 56, section 5.3.\n"));
511 if (ppd
->lang_encoding
!= NULL
)
514 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
516 else if (ppdversion
> 40)
520 if (!errors
&& !verbose
)
521 _cupsLangPuts(stdout
, _(" FAIL\n"));
523 _cupsLangPuts(stdout
,
524 _(" **FAIL** REQUIRED LanguageEncoding\n"
525 " REF: Pages 56-57, section 5.3.\n"));
531 if (ppd
->lang_version
!= NULL
)
534 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
540 if (!errors
&& !verbose
)
541 _cupsLangPuts(stdout
, _(" FAIL\n"));
543 _cupsLangPuts(stdout
,
544 _(" **FAIL** REQUIRED LanguageVersion\n"
545 " REF: Pages 57-58, section 5.3.\n"));
551 if (ppd
->manufacturer
!= NULL
)
553 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
554 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
558 if (!errors
&& !verbose
)
559 _cupsLangPuts(stdout
, _(" FAIL\n"));
561 _cupsLangPuts(stdout
,
562 _(" **FAIL** BAD Manufacturer (should be "
564 " REF: Page 211, table D.1.\n"));
569 else if (verbose
> 0)
570 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
572 else if (ppdversion
>= 43)
576 if (!errors
&& !verbose
)
577 _cupsLangPuts(stdout
, _(" FAIL\n"));
579 _cupsLangPuts(stdout
,
580 _(" **FAIL** REQUIRED Manufacturer\n"
581 " REF: Pages 58-59, section 5.3.\n"));
587 if (ppd
->modelname
!= NULL
)
589 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
590 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
597 if (!errors
&& !verbose
)
598 _cupsLangPuts(stdout
, _(" FAIL\n"));
600 _cupsLangPrintf(stdout
,
601 _(" **FAIL** BAD ModelName - \"%c\" not "
602 "allowed in string.\n"
603 " REF: Pages 59-60, section 5.3.\n"),
609 else if (verbose
> 0)
610 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
616 if (!errors
&& !verbose
)
617 _cupsLangPuts(stdout
, _(" FAIL\n"));
619 _cupsLangPuts(stdout
,
620 _(" **FAIL** REQUIRED ModelName\n"
621 " REF: Pages 59-60, section 5.3.\n"));
627 if (ppd
->nickname
!= NULL
)
630 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
636 if (!errors
&& !verbose
)
637 _cupsLangPuts(stdout
, _(" FAIL\n"));
639 _cupsLangPuts(stdout
,
640 _(" **FAIL** REQUIRED NickName\n"
641 " REF: Page 60, section 5.3.\n"));
647 if (ppdFindOption(ppd
, "PageSize") != NULL
)
650 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
656 if (!errors
&& !verbose
)
657 _cupsLangPuts(stdout
, _(" FAIL\n"));
659 _cupsLangPuts(stdout
,
660 _(" **FAIL** REQUIRED PageSize\n"
661 " REF: Pages 99-100, section 5.14.\n"));
667 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
670 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
676 if (!errors
&& !verbose
)
677 _cupsLangPuts(stdout
, _(" FAIL\n"));
679 _cupsLangPuts(stdout
,
680 _(" **FAIL** REQUIRED PageRegion\n"
681 " REF: Page 100, section 5.14.\n"));
687 if (ppd
->pcfilename
!= NULL
)
690 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
696 if (!errors
&& !verbose
)
697 _cupsLangPuts(stdout
, _(" FAIL\n"));
699 _cupsLangPuts(stdout
,
700 _(" **FAIL** REQUIRED PCFileName\n"
701 " REF: Pages 61-62, section 5.3.\n"));
707 if (ppd
->product
!= NULL
)
709 if (ppd
->product
[0] != '(' ||
710 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
714 if (!errors
&& !verbose
)
715 _cupsLangPuts(stdout
, _(" FAIL\n"));
717 _cupsLangPuts(stdout
,
718 _(" **FAIL** BAD Product - not \"(string)\".\n"
719 " REF: Page 62, section 5.3.\n"));
724 else if (verbose
> 0)
725 _cupsLangPuts(stdout
, _(" PASS Product\n"));
731 if (!errors
&& !verbose
)
732 _cupsLangPuts(stdout
, _(" FAIL\n"));
734 _cupsLangPuts(stdout
,
735 _(" **FAIL** REQUIRED Product\n"
736 " REF: Page 62, section 5.3.\n"));
742 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
745 char junkstr
[255]; /* Temp string */
746 int junkint
; /* Temp integer */
749 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
753 if (!errors
&& !verbose
)
754 _cupsLangPuts(stdout
, _(" FAIL\n"));
756 _cupsLangPuts(stdout
,
757 _(" **FAIL** BAD PSVersion - not \"(string) "
759 " REF: Pages 62-64, section 5.3.\n"));
764 else if (verbose
> 0)
765 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
771 if (!errors
&& !verbose
)
772 _cupsLangPuts(stdout
, _(" FAIL\n"));
774 _cupsLangPuts(stdout
,
775 _(" **FAIL** REQUIRED PSVersion\n"
776 " REF: Pages 62-64, section 5.3.\n"));
782 if (ppd
->shortnickname
!= NULL
)
784 if (strlen(ppd
->shortnickname
) > 31)
788 if (!errors
&& !verbose
)
789 _cupsLangPuts(stdout
, _(" FAIL\n"));
791 _cupsLangPuts(stdout
,
792 _(" **FAIL** BAD ShortNickName - longer "
794 " REF: Pages 64-65, section 5.3.\n"));
799 else if (verbose
> 0)
800 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
802 else if (ppdversion
>= 43)
806 if (!errors
&& !verbose
)
807 _cupsLangPuts(stdout
, _(" FAIL\n"));
809 _cupsLangPuts(stdout
,
810 _(" **FAIL** REQUIRED ShortNickName\n"
811 " REF: Page 64-65, section 5.3.\n"));
817 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
818 strstr(ppd
->patches
, "*End"))
822 if (!errors
&& !verbose
)
823 _cupsLangPuts(stdout
, _(" FAIL\n"));
825 _cupsLangPuts(stdout
,
826 _(" **FAIL** BAD JobPatchFile attribute in file\n"
827 " REF: Page 24, section 3.4.\n"));
834 * Check for page sizes without the corresponding ImageableArea or
835 * PaperDimension values...
838 if (ppd
->num_sizes
== 0)
842 if (!errors
&& !verbose
)
843 _cupsLangPuts(stdout
, _(" FAIL\n"));
845 _cupsLangPuts(stdout
,
846 _(" **FAIL** REQUIRED PageSize\n"
847 " REF: Page 41, section 5.\n"
848 " REF: Page 99, section 5.14.\n"));
855 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
858 * Don't check custom size...
861 if (!strcmp(size
->name
, "Custom"))
865 * Check for ImageableArea...
868 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
869 size
->right
== 0.0 && size
->top
== 0.0)
873 if (!errors
&& !verbose
)
874 _cupsLangPuts(stdout
, _(" FAIL\n"));
876 _cupsLangPrintf(stdout
,
877 _(" **FAIL** REQUIRED ImageableArea for "
879 " REF: Page 41, section 5.\n"
880 " REF: Page 102, section 5.15.\n"),
888 * Check for PaperDimension...
891 if (size
->width
== 0.0 && size
->length
== 0.0)
895 if (!errors
&& !verbose
)
896 _cupsLangPuts(stdout
, _(" FAIL\n"));
898 _cupsLangPrintf(stdout
,
899 _(" **FAIL** REQUIRED PaperDimension "
901 " REF: Page 41, section 5.\n"
902 " REF: Page 103, section 5.15.\n"),
912 * Check for valid Resolution, JCLResolution, or SetResolution values...
915 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
916 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
917 option
= ppdFindOption(ppd
, "SetResolution");
921 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
924 * Verify that all resolution options are of the form NNNdpi
928 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
929 if (ptr
> choice
->choice
&& xdpi
> 0)
932 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
939 if (xdpi
<= 0 || ydpi
<= 0 || strcmp(ptr
, "dpi"))
943 if (!errors
&& !verbose
)
944 _cupsLangPuts(stdout
, _(" FAIL\n"));
946 _cupsLangPrintf(stdout
,
947 _(" **FAIL** Bad %s choice %s!\n"
948 " REF: Page 84, section 5.9\n"),
949 option
->keyword
, choice
->choice
);
958 * Check for a duplex option, and for standard values...
961 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
962 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
963 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
964 option
= ppdFindOption(ppd
, "KD03Duplex");
968 if (ppdFindChoice(option
, "None") == NULL
)
972 if (!errors
&& !verbose
)
973 _cupsLangPuts(stdout
, _(" FAIL\n"));
975 _cupsLangPrintf(stdout
,
976 _(" **FAIL** REQUIRED %s does not define "
978 " REF: Page 122, section 5.17\n"),
985 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
986 if (strcmp(choice
->choice
, "None") &&
987 strcmp(choice
->choice
, "DuplexNoTumble") &&
988 strcmp(choice
->choice
, "DuplexTumble") &&
989 strcmp(choice
->choice
, "SimplexTumble"))
993 if (!errors
&& !verbose
)
994 _cupsLangPuts(stdout
, _(" FAIL\n"));
996 _cupsLangPrintf(stdout
,
997 _(" **FAIL** Bad %s choice %s!\n"
998 " REF: Page 122, section 5.17\n"),
999 option
->keyword
, choice
->choice
);
1006 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1010 * This file contains localizations, check them...
1013 char *languages
, /* Copy of attribute value */
1014 *langstart
, /* Start of current language */
1015 *langptr
, /* Pointer into languages */
1016 keyword
[PPD_MAX_NAME
],
1017 /* Localization keyword */
1018 ckeyword
[PPD_MAX_NAME
];
1019 /* Custom option keyword */
1020 ppd_coption_t
*coption
; /* Custom option */
1021 ppd_cparam_t
*cparam
; /* Custom parameter */
1022 cups_array_t
*langlist
; /* List of languages so far */
1023 char ll
[3]; /* Base language */
1026 languages
= strdup(attr
->value
);
1027 langlist
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
1029 for (langptr
= languages
; *langptr
;)
1032 * Skip leading whitespace...
1035 while (isspace(*langptr
& 255))
1042 * Find the end of this language name...
1045 for (langstart
= langptr
;
1046 *langptr
&& !isspace(*langptr
& 255);
1052 j
= strlen(langstart
);
1053 if (j
!= 2 && j
!= 5)
1057 if (!errors
&& !verbose
)
1058 _cupsLangPuts(stdout
, _(" FAIL\n"));
1060 _cupsLangPrintf(stdout
,
1061 _(" **FAIL** Bad language \"%s\"!\n"),
1069 cupsArrayAdd(langlist
, langstart
);
1072 * Loop through all options and choices...
1075 for (option
= ppdFirstOption(ppd
);
1077 option
= ppdNextOption(ppd
))
1079 snprintf(keyword
, sizeof(keyword
), "%s.Translation", langstart
);
1080 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
)
1084 if (!errors
&& !verbose
)
1085 _cupsLangPuts(stdout
, _(" FAIL\n"));
1087 _cupsLangPrintf(stdout
,
1088 _(" **FAIL** Missing \"%s\" translation "
1089 "string for option %s!\n"),
1090 langstart
, option
->keyword
);
1095 else if (!valid_utf8(attr
->text
))
1099 if (!errors
&& !verbose
)
1100 _cupsLangPuts(stdout
, _(" FAIL\n"));
1102 _cupsLangPrintf(stdout
,
1103 _(" **FAIL** Bad UTF-8 \"%s\" translation "
1104 "string for option %s!\n"),
1105 langstart
, option
->keyword
);
1111 for (ptr
= option
->text
; *ptr
; ptr
++)
1119 if (!errors
&& !verbose
)
1120 _cupsLangPuts(stdout
, _(" FAIL\n"));
1122 _cupsLangPrintf(stdout
,
1123 _(" **FAIL** Default translation "
1124 "string for option %s contains 8-bit "
1132 snprintf(keyword
, sizeof(keyword
), "%s.%s", langstart
,
1134 for (j
= 0; j
< option
->num_choices
; j
++)
1136 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
1137 (coption
= ppdFindCustomOption(ppd
,
1138 option
->keyword
)) != NULL
)
1140 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
1141 langstart
, option
->keyword
);
1143 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
1144 !valid_utf8(attr
->text
))
1148 if (!errors
&& !verbose
)
1149 _cupsLangPuts(stdout
, _(" FAIL\n"));
1151 _cupsLangPrintf(stdout
,
1152 _(" **FAIL** Bad UTF-8 \"%s\" "
1153 "translation string for option %s, "
1155 langstart
, ckeyword
+ 1 + strlen(langstart
),
1162 if (strcasecmp(option
->keyword
, "PageSize"))
1164 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
1166 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
1168 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
1169 langstart
, option
->keyword
);
1170 if ((attr
= ppdFindAttr(ppd
, ckeyword
, cparam
->name
)) == NULL
)
1174 if (!errors
&& !verbose
)
1175 _cupsLangPuts(stdout
, _(" FAIL\n"));
1177 _cupsLangPrintf(stdout
,
1178 _(" **FAIL** Missing \"%s\" "
1179 "translation string for option %s, "
1182 ckeyword
+ 1 + strlen(langstart
),
1188 else if (!valid_utf8(attr
->text
))
1192 if (!errors
&& !verbose
)
1193 _cupsLangPuts(stdout
, _(" FAIL\n"));
1195 _cupsLangPrintf(stdout
,
1196 _(" **FAIL** Bad UTF-8 \"%s\" "
1197 "translation string for option %s, "
1200 ckeyword
+ 1 + strlen(langstart
),
1209 else if ((attr
= ppdFindAttr(ppd
, keyword
, option
->choices
[j
].choice
)) == NULL
)
1213 if (!errors
&& !verbose
)
1214 _cupsLangPuts(stdout
, _(" FAIL\n"));
1216 _cupsLangPrintf(stdout
,
1217 _(" **FAIL** Missing \"%s\" "
1218 "translation string for option %s, "
1220 langstart
, option
->keyword
,
1221 option
->choices
[j
].choice
);
1226 else if (!valid_utf8(attr
->text
))
1230 if (!errors
&& !verbose
)
1231 _cupsLangPuts(stdout
, _(" FAIL\n"));
1233 _cupsLangPrintf(stdout
,
1234 _(" **FAIL** Bad UTF-8 \"%s\" "
1235 "translation string for option %s, "
1237 langstart
, option
->keyword
,
1238 option
->choices
[j
].choice
);
1244 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1252 if (!errors
&& !verbose
)
1253 _cupsLangPuts(stdout
, _(" FAIL\n"));
1255 _cupsLangPrintf(stdout
,
1256 _(" **FAIL** Default translation "
1257 "string for option %s choice %s contains "
1258 "8-bit characters!\n"),
1260 option
->choices
[j
].choice
);
1270 * Verify that we have the base language for each localized one...
1273 for (langptr
= (char *)cupsArrayFirst(langlist
);
1275 langptr
= (char *)cupsArrayNext(langlist
))
1279 * Lookup the base language...
1282 cupsArraySave(langlist
);
1284 strlcpy(ll
, langptr
, sizeof(ll
));
1286 if (!cupsArrayFind(langlist
, ll
))
1290 if (!errors
&& !verbose
)
1291 _cupsLangPuts(stdout
, _(" FAIL\n"));
1293 _cupsLangPrintf(stdout
,
1294 _(" **FAIL** No base translation \"%s\" "
1295 "is included in file!\n"), ll
);
1301 cupsArrayRestore(langlist
);
1305 * Free memory used for the languages...
1308 cupsArrayDelete(langlist
);
1312 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
1314 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
1316 char super
[16], /* Filter super type */
1317 type
[256], /* Filter type */
1318 program
[256]; /* Filter program */
1319 int cost
; /* Filter cost */
1323 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1328 if (!errors
&& !verbose
)
1329 _cupsLangPuts(stdout
, _(" FAIL\n"));
1331 _cupsLangPrintf(stdout
,
1332 _(" **FAIL** Bad cupsFilter value \"%s\"!\n"),
1333 attr
->value
? attr
->value
: "");
1340 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1341 strcmp(attr
->name
, "1284DeviceID"))
1345 if (!errors
&& !verbose
)
1346 _cupsLangPuts(stdout
, _(" FAIL\n"));
1348 _cupsLangPrintf(stdout
,
1349 _(" **FAIL** %s must be 1284DeviceID!\n"
1350 " REF: Page 72, section 5.5\n"),
1358 status
= ERROR_CONFORMANCE
;
1360 _cupsLangPuts(stdout
, _(" PASS\n"));
1364 check_basics(argv
[i
]);
1367 * Look for default keywords with no corresponding option...
1370 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1372 attr
= ppd
->attrs
[j
];
1374 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1375 !strcmp(attr
->name
, "DefaultColorSep") ||
1376 !strcmp(attr
->name
, "DefaultFont") ||
1377 !strcmp(attr
->name
, "DefaultImageableArea") ||
1378 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1379 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1380 !strcmp(attr
->name
, "DefaultScreenProc") ||
1381 !strcmp(attr
->name
, "DefaultTransfer"))
1384 if (!strncmp(attr
->name
, "Default", 7) &&
1385 !ppdFindOption(ppd
, attr
->name
+ 7))
1386 _cupsLangPrintf(stdout
,
1387 _(" WARN %s has no corresponding "
1393 * Check for old Duplex option names...
1396 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1397 option
= ppdFindOption(ppd
, "KD03Duplex");
1401 _cupsLangPrintf(stdout
,
1402 _(" WARN Duplex option keyword %s "
1403 "should be named Duplex or JCLDuplex!\n"
1404 " REF: Page 122, section 5.17\n"),
1408 ppdMarkDefaults(ppd
);
1409 if (ppdConflicts(ppd
))
1411 _cupsLangPuts(stdout
,
1412 _(" WARN Default choices conflicting!\n"));
1414 show_conflicts(ppd
);
1417 if (ppdversion
< 43)
1419 _cupsLangPrintf(stdout
,
1420 _(" WARN Obsolete PPD version %.1f!\n"
1421 " REF: Page 42, section 5.2.\n"),
1425 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1427 _cupsLangPuts(stdout
,
1428 _(" WARN LanguageEncoding required by PPD "
1430 " REF: Pages 56-57, section 5.3.\n"));
1433 if (!ppd
->manufacturer
&& ppdversion
< 43)
1435 _cupsLangPuts(stdout
,
1436 _(" WARN Manufacturer required by PPD "
1438 " REF: Pages 58-59, section 5.3.\n"));
1442 * Treat a PCFileName attribute longer than 12 characters as
1443 * a warning and not a hard error...
1446 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1448 _cupsLangPuts(stdout
,
1449 _(" WARN PCFileName longer than 8.3 in "
1450 "violation of PPD spec.\n"
1451 " REF: Pages 61-62, section 5.3.\n"));
1454 if (!ppd
->shortnickname
&& ppdversion
< 43)
1456 _cupsLangPuts(stdout
,
1457 _(" WARN ShortNickName required by PPD "
1459 " REF: Pages 64-65, section 5.3.\n"));
1463 * Check the Protocols line and flag PJL + BCP since TBCP is
1464 * usually used with PJL...
1469 if (strstr(ppd
->protocols
, "PJL") &&
1470 strstr(ppd
->protocols
, "BCP") &&
1471 !strstr(ppd
->protocols
, "TBCP"))
1473 _cupsLangPuts(stdout
,
1474 _(" WARN Protocols contains both PJL "
1475 "and BCP; expected TBCP.\n"
1476 " REF: Pages 78-79, section 5.7.\n"));
1479 if (strstr(ppd
->protocols
, "PJL") &&
1480 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1482 _cupsLangPuts(stdout
,
1483 _(" WARN Protocols contains PJL but JCL "
1484 "attributes are not set.\n"
1485 " REF: Pages 78-79, section 5.7.\n"));
1490 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1491 * which are errors according to the spec but won't cause problems
1492 * with CUPS specifically...
1495 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1496 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1498 len
= strlen(option
->keyword
);
1500 for (m
= 0, group2
= ppd
->groups
;
1501 m
< ppd
->num_groups
;
1503 for (n
= 0, option2
= group2
->options
;
1504 n
< group2
->num_options
;
1506 if (option
!= option2
&&
1507 len
< strlen(option2
->keyword
) &&
1508 !strncmp(option
->keyword
, option2
->keyword
, len
))
1510 _cupsLangPrintf(stdout
,
1511 _(" WARN %s shares a common "
1513 " REF: Page 15, section "
1515 option
->keyword
, option2
->keyword
);
1523 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1525 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1529 * Then list the options, if "-v" was provided...
1534 _cupsLangPrintf(stdout
,
1536 " language_level = %d\n"
1537 " color_device = %s\n"
1538 " variable_sizes = %s\n"
1539 " landscape = %d\n",
1540 ppd
->language_level
,
1541 ppd
->color_device
? "TRUE" : "FALSE",
1542 ppd
->variable_sizes
? "TRUE" : "FALSE",
1545 switch (ppd
->colorspace
)
1548 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1551 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1554 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1557 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1560 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1564 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1565 ppd
->num_emulations
);
1566 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1567 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1568 j
, ppd
->emulations
[j
].name
);
1570 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1571 ppd
->lang_encoding
);
1572 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1574 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1575 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1576 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1577 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1579 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1580 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1581 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1582 ppd
->shortnickname
);
1583 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1584 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1586 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1587 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1589 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1592 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1594 _cupsLangPrintf(stdout
,
1595 " options[%d] = %s (%s) %s %s %.0f "
1597 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1598 sections
[option
->section
], option
->order
,
1599 option
->num_choices
);
1601 if (!strcmp(option
->keyword
, "PageSize") ||
1602 !strcmp(option
->keyword
, "PageRegion"))
1604 for (m
= option
->num_choices
, choice
= option
->choices
;
1608 size
= ppdPageSize(ppd
, choice
->choice
);
1611 _cupsLangPrintf(stdout
,
1613 choice
->choice
, choice
->text
);
1615 _cupsLangPrintf(stdout
,
1616 " %s (%s) = %.2fx%.2fin "
1617 "(%.1f,%.1f,%.1f,%.1f)",
1618 choice
->choice
, choice
->text
,
1619 size
->width
/ 72.0, size
->length
/ 72.0,
1620 size
->left
/ 72.0, size
->bottom
/ 72.0,
1621 size
->right
/ 72.0, size
->top
/ 72.0);
1623 if (!strcmp(option
->defchoice
, choice
->choice
))
1624 _cupsLangPuts(stdout
, " *\n");
1626 _cupsLangPuts(stdout
, "\n");
1631 for (m
= option
->num_choices
, choice
= option
->choices
;
1635 _cupsLangPrintf(stdout
, " %s (%s)",
1636 choice
->choice
, choice
->text
);
1638 if (!strcmp(option
->defchoice
, choice
->choice
))
1639 _cupsLangPuts(stdout
, " *\n");
1641 _cupsLangPuts(stdout
, "\n");
1647 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1649 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1650 _cupsLangPrintf(stdout
,
1651 " profiles[%d] = %s/%s %.3f %.3f "
1652 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1653 j
, ppd
->profiles
[j
].resolution
,
1654 ppd
->profiles
[j
].media_type
,
1655 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1656 ppd
->profiles
[j
].matrix
[0][0],
1657 ppd
->profiles
[j
].matrix
[0][1],
1658 ppd
->profiles
[j
].matrix
[0][2],
1659 ppd
->profiles
[j
].matrix
[1][0],
1660 ppd
->profiles
[j
].matrix
[1][1],
1661 ppd
->profiles
[j
].matrix
[1][2],
1662 ppd
->profiles
[j
].matrix
[2][0],
1663 ppd
->profiles
[j
].matrix
[2][1],
1664 ppd
->profiles
[j
].matrix
[2][2]);
1666 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1667 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1668 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1671 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1672 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1673 _cupsLangPrintf(stdout
,
1674 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1675 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1676 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1677 ppd
->attrs
[j
]->text
,
1678 ppd
->attrs
[j
]->value
?
1679 ppd
->attrs
[j
]->value
: "(null)");
1693 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1697 check_basics(const char *filename
) /* I - PPD file to check */
1699 cups_file_t
*fp
; /* File pointer */
1700 int ch
; /* Current character */
1701 int col
, /* Current column */
1702 whitespace
; /* Only seen whitespace? */
1703 int eol
; /* Line endings */
1704 int linenum
; /* Line number */
1705 int mixed
; /* Mixed line endings? */
1708 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1717 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1719 if (ch
== '\r' || ch
== '\n')
1723 if (eol
== EOL_NONE
)
1725 else if (eol
!= EOL_LF
)
1728 else if (ch
== '\r')
1730 if (cupsFilePeekChar(fp
) == '\n')
1732 cupsFileGetChar(fp
);
1734 if (eol
== EOL_NONE
)
1739 else if (eol
== EOL_NONE
)
1745 if (col
> 0 && whitespace
)
1746 _cupsLangPrintf(stdout
,
1747 _(" WARN Line %d only contains whitespace!\n"),
1756 if (ch
!= ' ' && ch
!= '\t')
1764 _cupsLangPuts(stdout
,
1765 _(" WARN File contains a mix of CR, LF, and "
1766 "CR LF line endings!\n"));
1768 if (eol
== EOL_CRLF
)
1769 _cupsLangPuts(stdout
,
1770 _(" WARN Non-Windows PPD files should use lines "
1771 "ending with only LF, not CR LF!\n"));
1778 * 'show_conflicts()' - Show option conflicts in a PPD file.
1782 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
1784 int i
, j
; /* Looping variables */
1785 ppd_const_t
*c
; /* Current constraint */
1786 ppd_option_t
*o1
, *o2
; /* Options */
1787 ppd_choice_t
*c1
, *c2
; /* Choices */
1791 * Loop through all of the UI constraints and report any options
1795 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
1798 * Grab pointers to the first option...
1801 o1
= ppdFindOption(ppd
, c
->option1
);
1805 else if (c
->choice1
[0] != '\0')
1808 * This constraint maps to a specific choice.
1811 c1
= ppdFindChoice(o1
, c
->choice1
);
1816 * This constraint applies to any choice for this option.
1819 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
1824 !strcasecmp(c1
->choice
, "None") ||
1825 !strcasecmp(c1
->choice
, "Off") ||
1826 !strcasecmp(c1
->choice
, "False"))
1831 * Grab pointers to the second option...
1834 o2
= ppdFindOption(ppd
, c
->option2
);
1838 else if (c
->choice2
[0] != '\0')
1841 * This constraint maps to a specific choice.
1844 c2
= ppdFindChoice(o2
, c
->choice2
);
1849 * This constraint applies to any choice for this option.
1852 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
1857 !strcasecmp(c2
->choice
, "None") ||
1858 !strcasecmp(c2
->choice
, "Off") ||
1859 !strcasecmp(c2
->choice
, "False"))
1864 * If both options are marked then there is a conflict...
1867 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
1868 _cupsLangPrintf(stdout
,
1869 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
1870 " (constraint=\"%s %s %s %s\")\n"),
1871 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
1872 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1878 * 'usage()' - Show program usage...
1884 _cupsLangPuts(stdout
,
1885 _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] "
1886 "[... filenameN.ppd[.gz]]\n"
1887 " program | cupstestppd [-q] [-r] [-v[v]] -\n"));
1894 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
1897 int /* O - 1 if valid, 0 if not */
1898 valid_utf8(const char *s
) /* I - String to check */
1905 * Check for valid UTF-8 sequence...
1908 if ((*s
& 0xc0) == 0x80)
1909 return (0); /* Illegal suffix byte */
1910 else if ((*s
& 0xe0) == 0xc0)
1913 * 2-byte sequence...
1918 if ((*s
& 0xc0) != 0x80)
1919 return (0); /* Missing suffix byte */
1921 else if ((*s
& 0xf0) == 0xe0)
1924 * 3-byte sequence...
1929 if ((*s
& 0xc0) != 0x80)
1930 return (0); /* Missing suffix byte */
1934 if ((*s
& 0xc0) != 0x80)
1935 return (0); /* Missing suffix byte */
1937 else if ((*s
& 0xf8) == 0xf0)
1940 * 4-byte sequence...
1945 if ((*s
& 0xc0) != 0x80)
1946 return (0); /* Missing suffix byte */
1950 if ((*s
& 0xc0) != 0x80)
1951 return (0); /* Missing suffix byte */
1955 if ((*s
& 0xc0) != 0x80)
1956 return (0); /* Missing suffix byte */
1959 return (0); /* Bad sequence */
1970 * End of "$Id: cupstestppd.c 6430 2007-04-02 14:01:55Z mike $".