2 * "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z 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>
49 * Error warning overrides...
58 WARN_TRANSLATIONS
= 8,
94 void check_basics(const char *filename
);
95 int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
96 int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
97 int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
98 int verbose
, int warn
);
99 int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
, int warn
);
100 void show_conflicts(ppd_file_t
*ppd
);
102 int valid_utf8(const char *s
);
106 * 'main()' - Main entry for test program.
109 int /* O - Exit status */
110 main(int argc
, /* I - Number of command-line args */
111 char *argv
[]) /* I - Command-line arguments */
113 int i
, j
, k
, m
, n
; /* Looping vars */
114 int len
; /* Length of option name */
115 char *opt
; /* Option character */
116 const char *ptr
; /* Pointer into string */
117 int files
; /* Number of files */
118 int verbose
; /* Want verbose output? */
119 int warn
; /* Which errors to just warn about */
120 int status
; /* Exit status */
121 int errors
; /* Number of conformance errors */
122 int ppdversion
; /* PPD spec version in PPD file */
123 ppd_status_t error
; /* Status of ppdOpen*() */
124 int line
; /* Line number for error */
125 struct stat statbuf
; /* File information */
126 char pathprog
[1024], /* Complete path to program/filter */
127 *root
; /* Root directory */
128 int xdpi
, /* X resolution */
129 ydpi
; /* Y resolution */
130 ppd_file_t
*ppd
; /* PPD file record */
131 ppd_attr_t
*attr
; /* PPD attribute */
132 ppd_size_t
*size
; /* Size record */
133 ppd_group_t
*group
; /* UI group */
134 ppd_option_t
*option
; /* Standard UI option */
135 ppd_group_t
*group2
; /* UI group */
136 ppd_option_t
*option2
; /* Standard UI option */
137 ppd_choice_t
*choice
; /* Standard UI option choice */
138 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
139 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
140 "JCL", "PAGE", "PROLOG" };
143 _cupsSetLocale(argv
);
146 * Display PPD files for each file listed on the command-line...
149 ppdSetConformance(PPD_CONFORM_STRICT
);
158 for (i
= 1; i
< argc
; i
++)
159 if (argv
[i
][0] == '-' && argv
[i
][1])
161 for (opt
= argv
[i
] + 1; *opt
; opt
++)
164 case 'R' : /* Alternate root directory */
173 case 'W' : /* Turn errors into warnings */
179 if (!strcmp(argv
[i
], "none"))
181 else if (!strcmp(argv
[i
], "constraints"))
182 warn
|= WARN_CONSTRAINTS
;
183 else if (!strcmp(argv
[i
], "defaults"))
184 warn
|= WARN_DEFAULTS
;
185 else if (!strcmp(argv
[i
], "filters"))
186 warn
|= WARN_FILTERS
;
187 else if (!strcmp(argv
[i
], "translations"))
188 warn
|= WARN_TRANSLATIONS
;
189 else if (!strcmp(argv
[i
], "all"))
195 case 'q' : /* Quiet mode */
198 _cupsLangPuts(stderr
,
199 _("cupstestppd: The -q option is incompatible "
200 "with the -v option.\n"));
207 case 'r' : /* Relaxed mode */
208 ppdSetConformance(PPD_CONFORM_RELAXED
);
211 case 'v' : /* Verbose mode */
214 _cupsLangPuts(stderr
,
215 _("cupstestppd: The -v option is incompatible "
216 "with the -q option.\n"));
231 * Open the PPD file...
234 if (files
&& verbose
>= 0)
235 _cupsLangPuts(stdout
, "\n");
239 if (argv
[i
][0] == '-')
248 ppd
= ppdOpen(stdin
);
253 * Read from a file...
257 printf("%s:", argv
[i
]);
259 ppd
= ppdOpenFile(argv
[i
]);
264 error
= ppdLastError(&line
);
266 if (error
<= PPD_ALLOC_ERROR
)
268 status
= ERROR_FILE_OPEN
;
271 _cupsLangPrintf(stdout
,
273 " **FAIL** Unable to open PPD file - %s\n"),
278 status
= ERROR_PPD_FORMAT
;
282 _cupsLangPrintf(stdout
,
284 " **FAIL** Unable to open PPD file - "
286 ppdErrorString(error
), line
);
290 case PPD_MISSING_PPDADOBE4
:
291 _cupsLangPuts(stdout
,
292 _(" REF: Page 42, section 5.2.\n"));
294 case PPD_MISSING_VALUE
:
295 _cupsLangPuts(stdout
,
296 _(" REF: Page 20, section 3.4.\n"));
298 case PPD_BAD_OPEN_GROUP
:
299 case PPD_NESTED_OPEN_GROUP
:
300 _cupsLangPuts(stdout
,
301 _(" REF: Pages 45-46, section 5.2.\n"));
303 case PPD_BAD_OPEN_UI
:
304 case PPD_NESTED_OPEN_UI
:
305 _cupsLangPuts(stdout
,
306 _(" REF: Pages 42-45, section 5.2.\n"));
308 case PPD_BAD_ORDER_DEPENDENCY
:
309 _cupsLangPuts(stdout
,
310 _(" REF: Pages 48-49, section 5.2.\n"));
312 case PPD_BAD_UI_CONSTRAINTS
:
313 _cupsLangPuts(stdout
,
314 _(" REF: Pages 52-54, section 5.2.\n"));
316 case PPD_MISSING_ASTERISK
:
317 _cupsLangPuts(stdout
,
318 _(" REF: Page 15, section 3.2.\n"));
320 case PPD_LINE_TOO_LONG
:
321 _cupsLangPuts(stdout
,
322 _(" REF: Page 15, section 3.1.\n"));
324 case PPD_ILLEGAL_CHARACTER
:
325 _cupsLangPuts(stdout
,
326 _(" REF: Page 15, section 3.1.\n"));
328 case PPD_ILLEGAL_MAIN_KEYWORD
:
329 _cupsLangPuts(stdout
,
330 _(" REF: Pages 16-17, section 3.2.\n"));
332 case PPD_ILLEGAL_OPTION_KEYWORD
:
333 _cupsLangPuts(stdout
,
334 _(" REF: Page 19, section 3.3.\n"));
336 case PPD_ILLEGAL_TRANSLATION
:
337 _cupsLangPuts(stdout
,
338 _(" REF: Page 27, section 3.5.\n"));
344 check_basics(argv
[i
]);
352 * Show the header and then perform basic conformance tests (limited
353 * only by what the CUPS PPD functions actually load...)
360 _cupsLangPuts(stdout
,
361 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
363 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
365 ppdversion
= (int)(10 * atof(attr
->value
) + 0.5);
368 * Look for default keywords with no matching option...
371 if (!(warn
& WARN_DEFAULTS
))
372 errors
= check_defaults(ppd
, errors
, verbose
, 0);
374 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
378 if (!errors
&& !verbose
)
379 _cupsLangPuts(stdout
, _(" FAIL\n"));
381 _cupsLangPuts(stdout
,
382 _(" **FAIL** REQUIRED DefaultImageableArea\n"
383 " REF: Page 102, section 5.15.\n"));
388 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
389 strcmp(attr
->value
, "Unknown"))
393 if (!errors
&& !verbose
)
394 _cupsLangPuts(stdout
, _(" FAIL\n"));
396 _cupsLangPrintf(stdout
,
397 _(" **FAIL** BAD DefaultImageableArea %s!\n"
398 " REF: Page 102, section 5.15.\n"),
407 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
410 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
414 if (!errors
&& !verbose
)
415 _cupsLangPuts(stdout
, _(" FAIL\n"));
417 _cupsLangPuts(stdout
,
418 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
419 " REF: Page 103, section 5.15.\n"));
424 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
425 strcmp(attr
->value
, "Unknown"))
429 if (!errors
&& !verbose
)
430 _cupsLangPuts(stdout
, _(" FAIL\n"));
432 _cupsLangPrintf(stdout
,
433 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
434 " REF: Page 103, section 5.15.\n"),
440 else if (verbose
> 0)
441 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
443 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
444 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
447 * Verify that we have a default choice...
450 if (option
->defchoice
[0])
452 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
453 strcmp(option
->defchoice
, "Unknown"))
457 if (!errors
&& !verbose
)
458 _cupsLangPuts(stdout
, _(" FAIL\n"));
460 _cupsLangPrintf(stdout
,
461 _(" **FAIL** BAD Default%s %s\n"
462 " REF: Page 40, section 4.5.\n"),
463 option
->keyword
, option
->defchoice
);
468 else if (verbose
> 0)
469 _cupsLangPrintf(stdout
,
470 _(" PASS Default%s\n"),
477 if (!errors
&& !verbose
)
478 _cupsLangPuts(stdout
, _(" FAIL\n"));
480 _cupsLangPrintf(stdout
,
481 _(" **FAIL** REQUIRED Default%s\n"
482 " REF: Page 40, section 4.5.\n"),
490 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
493 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
499 if (!errors
&& !verbose
)
500 _cupsLangPuts(stdout
, _(" FAIL\n"));
502 _cupsLangPuts(stdout
,
503 _(" **FAIL** REQUIRED FileVersion\n"
504 " REF: Page 56, section 5.3.\n"));
510 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
513 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
519 if (!errors
&& !verbose
)
520 _cupsLangPuts(stdout
, _(" FAIL\n"));
522 _cupsLangPuts(stdout
,
523 _(" **FAIL** REQUIRED FormatVersion\n"
524 " REF: Page 56, section 5.3.\n"));
530 if (ppd
->lang_encoding
!= NULL
)
533 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
535 else if (ppdversion
> 40)
539 if (!errors
&& !verbose
)
540 _cupsLangPuts(stdout
, _(" FAIL\n"));
542 _cupsLangPuts(stdout
,
543 _(" **FAIL** REQUIRED LanguageEncoding\n"
544 " REF: Pages 56-57, section 5.3.\n"));
550 if (ppd
->lang_version
!= NULL
)
553 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
559 if (!errors
&& !verbose
)
560 _cupsLangPuts(stdout
, _(" FAIL\n"));
562 _cupsLangPuts(stdout
,
563 _(" **FAIL** REQUIRED LanguageVersion\n"
564 " REF: Pages 57-58, section 5.3.\n"));
570 if (ppd
->manufacturer
!= NULL
)
572 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
573 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
577 if (!errors
&& !verbose
)
578 _cupsLangPuts(stdout
, _(" FAIL\n"));
580 _cupsLangPuts(stdout
,
581 _(" **FAIL** BAD Manufacturer (should be "
583 " REF: Page 211, table D.1.\n"));
588 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
589 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
593 if (!errors
&& !verbose
)
594 _cupsLangPuts(stdout
, _(" FAIL\n"));
596 _cupsLangPuts(stdout
,
597 _(" **FAIL** BAD Manufacturer (should be "
599 " REF: Page 211, table D.1.\n"));
604 else if (verbose
> 0)
605 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
607 else if (ppdversion
>= 43)
611 if (!errors
&& !verbose
)
612 _cupsLangPuts(stdout
, _(" FAIL\n"));
614 _cupsLangPuts(stdout
,
615 _(" **FAIL** REQUIRED Manufacturer\n"
616 " REF: Pages 58-59, section 5.3.\n"));
622 if (ppd
->modelname
!= NULL
)
624 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
625 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
632 if (!errors
&& !verbose
)
633 _cupsLangPuts(stdout
, _(" FAIL\n"));
635 _cupsLangPrintf(stdout
,
636 _(" **FAIL** BAD ModelName - \"%c\" not "
637 "allowed in string.\n"
638 " REF: Pages 59-60, section 5.3.\n"),
644 else if (verbose
> 0)
645 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
651 if (!errors
&& !verbose
)
652 _cupsLangPuts(stdout
, _(" FAIL\n"));
654 _cupsLangPuts(stdout
,
655 _(" **FAIL** REQUIRED ModelName\n"
656 " REF: Pages 59-60, section 5.3.\n"));
662 if (ppd
->nickname
!= NULL
)
665 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
671 if (!errors
&& !verbose
)
672 _cupsLangPuts(stdout
, _(" FAIL\n"));
674 _cupsLangPuts(stdout
,
675 _(" **FAIL** REQUIRED NickName\n"
676 " REF: Page 60, section 5.3.\n"));
682 if (ppdFindOption(ppd
, "PageSize") != NULL
)
685 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
691 if (!errors
&& !verbose
)
692 _cupsLangPuts(stdout
, _(" FAIL\n"));
694 _cupsLangPuts(stdout
,
695 _(" **FAIL** REQUIRED PageSize\n"
696 " REF: Pages 99-100, section 5.14.\n"));
702 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
705 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
711 if (!errors
&& !verbose
)
712 _cupsLangPuts(stdout
, _(" FAIL\n"));
714 _cupsLangPuts(stdout
,
715 _(" **FAIL** REQUIRED PageRegion\n"
716 " REF: Page 100, section 5.14.\n"));
722 if (ppd
->pcfilename
!= NULL
)
725 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
731 if (!errors
&& !verbose
)
732 _cupsLangPuts(stdout
, _(" FAIL\n"));
734 _cupsLangPuts(stdout
,
735 _(" **FAIL** REQUIRED PCFileName\n"
736 " REF: Pages 61-62, section 5.3.\n"));
742 if (ppd
->product
!= NULL
)
744 if (ppd
->product
[0] != '(' ||
745 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
749 if (!errors
&& !verbose
)
750 _cupsLangPuts(stdout
, _(" FAIL\n"));
752 _cupsLangPuts(stdout
,
753 _(" **FAIL** BAD Product - not \"(string)\".\n"
754 " REF: Page 62, section 5.3.\n"));
759 else if (verbose
> 0)
760 _cupsLangPuts(stdout
, _(" PASS Product\n"));
766 if (!errors
&& !verbose
)
767 _cupsLangPuts(stdout
, _(" FAIL\n"));
769 _cupsLangPuts(stdout
,
770 _(" **FAIL** REQUIRED Product\n"
771 " REF: Page 62, section 5.3.\n"));
777 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
780 char junkstr
[255]; /* Temp string */
781 int junkint
; /* Temp integer */
784 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
788 if (!errors
&& !verbose
)
789 _cupsLangPuts(stdout
, _(" FAIL\n"));
791 _cupsLangPuts(stdout
,
792 _(" **FAIL** BAD PSVersion - not \"(string) "
794 " REF: Pages 62-64, section 5.3.\n"));
799 else if (verbose
> 0)
800 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
806 if (!errors
&& !verbose
)
807 _cupsLangPuts(stdout
, _(" FAIL\n"));
809 _cupsLangPuts(stdout
,
810 _(" **FAIL** REQUIRED PSVersion\n"
811 " REF: Pages 62-64, section 5.3.\n"));
817 if (ppd
->shortnickname
!= NULL
)
819 if (strlen(ppd
->shortnickname
) > 31)
823 if (!errors
&& !verbose
)
824 _cupsLangPuts(stdout
, _(" FAIL\n"));
826 _cupsLangPuts(stdout
,
827 _(" **FAIL** BAD ShortNickName - longer "
829 " REF: Pages 64-65, section 5.3.\n"));
834 else if (verbose
> 0)
835 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
837 else if (ppdversion
>= 43)
841 if (!errors
&& !verbose
)
842 _cupsLangPuts(stdout
, _(" FAIL\n"));
844 _cupsLangPuts(stdout
,
845 _(" **FAIL** REQUIRED ShortNickName\n"
846 " REF: Page 64-65, section 5.3.\n"));
852 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
853 strstr(ppd
->patches
, "*End"))
857 if (!errors
&& !verbose
)
858 _cupsLangPuts(stdout
, _(" FAIL\n"));
860 _cupsLangPuts(stdout
,
861 _(" **FAIL** BAD JobPatchFile attribute in file\n"
862 " REF: Page 24, section 3.4.\n"));
869 * Check for page sizes without the corresponding ImageableArea or
870 * PaperDimension values...
873 if (ppd
->num_sizes
== 0)
877 if (!errors
&& !verbose
)
878 _cupsLangPuts(stdout
, _(" FAIL\n"));
880 _cupsLangPuts(stdout
,
881 _(" **FAIL** REQUIRED PageSize\n"
882 " REF: Page 41, section 5.\n"
883 " REF: Page 99, section 5.14.\n"));
890 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
893 * Don't check custom size...
896 if (!strcmp(size
->name
, "Custom"))
900 * Check for ImageableArea...
903 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
904 size
->right
== 0.0 && size
->top
== 0.0)
908 if (!errors
&& !verbose
)
909 _cupsLangPuts(stdout
, _(" FAIL\n"));
911 _cupsLangPrintf(stdout
,
912 _(" **FAIL** REQUIRED ImageableArea for "
914 " REF: Page 41, section 5.\n"
915 " REF: Page 102, section 5.15.\n"),
923 * Check for PaperDimension...
926 if (size
->width
== 0.0 && size
->length
== 0.0)
930 if (!errors
&& !verbose
)
931 _cupsLangPuts(stdout
, _(" FAIL\n"));
933 _cupsLangPrintf(stdout
,
934 _(" **FAIL** REQUIRED PaperDimension "
936 " REF: Page 41, section 5.\n"
937 " REF: Page 103, section 5.15.\n"),
947 * Check for valid Resolution, JCLResolution, or SetResolution values...
950 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
951 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
952 option
= ppdFindOption(ppd
, "SetResolution");
956 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
959 * Verify that all resolution options are of the form NNNdpi
963 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
964 if (ptr
> choice
->choice
&& xdpi
> 0)
967 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
974 if (xdpi
<= 0 || ydpi
<= 0 || strcmp(ptr
, "dpi"))
978 if (!errors
&& !verbose
)
979 _cupsLangPuts(stdout
, _(" FAIL\n"));
981 _cupsLangPrintf(stdout
,
982 _(" **FAIL** Bad %s choice %s!\n"
983 " REF: Page 84, section 5.9\n"),
984 option
->keyword
, choice
->choice
);
993 * Check for a duplex option, and for standard values...
996 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
997 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
998 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
999 option
= ppdFindOption(ppd
, "KD03Duplex");
1003 if (ppdFindChoice(option
, "None") == NULL
)
1007 if (!errors
&& !verbose
)
1008 _cupsLangPuts(stdout
, _(" FAIL\n"));
1010 _cupsLangPrintf(stdout
,
1011 _(" **FAIL** REQUIRED %s does not define "
1013 " REF: Page 122, section 5.17\n"),
1020 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
1021 if (strcmp(choice
->choice
, "None") &&
1022 strcmp(choice
->choice
, "DuplexNoTumble") &&
1023 strcmp(choice
->choice
, "DuplexTumble") &&
1024 strcmp(choice
->choice
, "SimplexTumble"))
1028 if (!errors
&& !verbose
)
1029 _cupsLangPuts(stdout
, _(" FAIL\n"));
1031 _cupsLangPrintf(stdout
,
1032 _(" **FAIL** Bad %s choice %s!\n"
1033 " REF: Page 122, section 5.17\n"),
1034 option
->keyword
, choice
->choice
);
1041 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1042 strcmp(attr
->name
, "1284DeviceID"))
1046 if (!errors
&& !verbose
)
1047 _cupsLangPuts(stdout
, _(" FAIL\n"));
1049 _cupsLangPrintf(stdout
,
1050 _(" **FAIL** %s must be 1284DeviceID!\n"
1051 " REF: Page 72, section 5.5\n"),
1058 if (!(warn
& WARN_CONSTRAINTS
))
1059 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1061 if (!(warn
& WARN_FILTERS
))
1062 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1064 if (!(warn
& WARN_TRANSLATIONS
))
1065 errors
= check_translations(ppd
, errors
, verbose
, 0);
1067 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1071 * This file contains localizations, check for conformance of the
1072 * base translation...
1075 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1077 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1079 if (!errors
&& !verbose
)
1080 _cupsLangPuts(stdout
, _(" FAIL\n"));
1083 _cupsLangPrintf(stderr
,
1084 _(" **FAIL** Bad LanguageEncoding %s - "
1085 "must be ISOLatin1!\n"),
1086 attr
->value
? attr
->value
: "(null)");
1091 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1093 if (!errors
&& !verbose
)
1094 _cupsLangPuts(stdout
, _(" FAIL\n"));
1097 _cupsLangPrintf(stderr
,
1098 _(" **FAIL** Bad LanguageVersion %s - "
1099 "must be English!\n"),
1100 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1106 * Loop through all options and choices...
1109 for (option
= ppdFirstOption(ppd
);
1111 option
= ppdNextOption(ppd
))
1114 * Check for special characters outside A0 to BF, F7, or F8
1115 * that are used for languages other than English.
1118 for (ptr
= option
->text
; *ptr
; ptr
++)
1119 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1120 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1125 if (!errors
&& !verbose
)
1126 _cupsLangPuts(stdout
, _(" FAIL\n"));
1129 _cupsLangPrintf(stdout
,
1130 _(" **FAIL** Default translation "
1131 "string for option %s contains 8-bit "
1138 for (j
= 0; j
< option
->num_choices
; j
++)
1141 * Check for special characters outside A0 to BF, F7, or F8
1142 * that are used for languages other than English.
1145 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1146 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1147 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1152 if (!errors
&& !verbose
)
1153 _cupsLangPuts(stdout
, _(" FAIL\n"));
1156 _cupsLangPrintf(stdout
,
1157 _(" **FAIL** Default translation "
1158 "string for option %s choice %s contains "
1159 "8-bit characters!\n"),
1161 option
->choices
[j
].choice
);
1171 * Final pass/fail notification...
1175 status
= ERROR_CONFORMANCE
;
1177 _cupsLangPuts(stdout
, _(" PASS\n"));
1181 check_basics(argv
[i
]);
1183 if (warn
& WARN_CONSTRAINTS
)
1184 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1186 if (warn
& WARN_DEFAULTS
)
1187 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1189 if (warn
& WARN_FILTERS
)
1190 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1192 if (warn
& WARN_TRANSLATIONS
)
1193 errors
= check_translations(ppd
, errors
, verbose
, 1);
1196 * Look for default keywords with no corresponding option...
1199 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1201 attr
= ppd
->attrs
[j
];
1203 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1204 !strcmp(attr
->name
, "DefaultColorSep") ||
1205 !strcmp(attr
->name
, "DefaultFont") ||
1206 !strcmp(attr
->name
, "DefaultImageableArea") ||
1207 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1208 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1209 !strcmp(attr
->name
, "DefaultScreenProc") ||
1210 !strcmp(attr
->name
, "DefaultTransfer"))
1213 if (!strncmp(attr
->name
, "Default", 7) &&
1214 !ppdFindOption(ppd
, attr
->name
+ 7))
1215 _cupsLangPrintf(stdout
,
1216 _(" WARN %s has no corresponding "
1222 * Check for old Duplex option names...
1225 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1226 option
= ppdFindOption(ppd
, "KD03Duplex");
1230 _cupsLangPrintf(stdout
,
1231 _(" WARN Duplex option keyword %s "
1232 "should be named Duplex or JCLDuplex!\n"
1233 " REF: Page 122, section 5.17\n"),
1237 ppdMarkDefaults(ppd
);
1238 if (ppdConflicts(ppd
))
1240 _cupsLangPuts(stdout
,
1241 _(" WARN Default choices conflicting!\n"));
1243 show_conflicts(ppd
);
1246 if (ppdversion
< 43)
1248 _cupsLangPrintf(stdout
,
1249 _(" WARN Obsolete PPD version %.1f!\n"
1250 " REF: Page 42, section 5.2.\n"),
1254 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1256 _cupsLangPuts(stdout
,
1257 _(" WARN LanguageEncoding required by PPD "
1259 " REF: Pages 56-57, section 5.3.\n"));
1262 if (!ppd
->manufacturer
&& ppdversion
< 43)
1264 _cupsLangPuts(stdout
,
1265 _(" WARN Manufacturer required by PPD "
1267 " REF: Pages 58-59, section 5.3.\n"));
1271 * Treat a PCFileName attribute longer than 12 characters as
1272 * a warning and not a hard error...
1275 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1277 _cupsLangPuts(stdout
,
1278 _(" WARN PCFileName longer than 8.3 in "
1279 "violation of PPD spec.\n"
1280 " REF: Pages 61-62, section 5.3.\n"));
1283 if (!ppd
->shortnickname
&& ppdversion
< 43)
1285 _cupsLangPuts(stdout
,
1286 _(" WARN ShortNickName required by PPD "
1288 " REF: Pages 64-65, section 5.3.\n"));
1292 * Check the Protocols line and flag PJL + BCP since TBCP is
1293 * usually used with PJL...
1298 if (strstr(ppd
->protocols
, "PJL") &&
1299 strstr(ppd
->protocols
, "BCP") &&
1300 !strstr(ppd
->protocols
, "TBCP"))
1302 _cupsLangPuts(stdout
,
1303 _(" WARN Protocols contains both PJL "
1304 "and BCP; expected TBCP.\n"
1305 " REF: Pages 78-79, section 5.7.\n"));
1308 if (strstr(ppd
->protocols
, "PJL") &&
1309 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1311 _cupsLangPuts(stdout
,
1312 _(" WARN Protocols contains PJL but JCL "
1313 "attributes are not set.\n"
1314 " REF: Pages 78-79, section 5.7.\n"));
1319 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1320 * which are errors according to the spec but won't cause problems
1321 * with CUPS specifically...
1324 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1325 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1327 len
= strlen(option
->keyword
);
1329 for (m
= 0, group2
= ppd
->groups
;
1330 m
< ppd
->num_groups
;
1332 for (n
= 0, option2
= group2
->options
;
1333 n
< group2
->num_options
;
1335 if (option
!= option2
&&
1336 len
< strlen(option2
->keyword
) &&
1337 !strncmp(option
->keyword
, option2
->keyword
, len
))
1339 _cupsLangPrintf(stdout
,
1340 _(" WARN %s shares a common "
1342 " REF: Page 15, section "
1344 option
->keyword
, option2
->keyword
);
1353 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
1355 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
1359 if (attr
->value
[0] == '/')
1360 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, attr
->value
);
1363 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
1366 if (*ptr
== '/' || !*root
)
1367 snprintf(pathprog
, sizeof(pathprog
), "%s%s/profiles/%s", root
,
1370 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/profiles/%s", root
,
1375 if (!attr
->value
|| !attr
->value
[0] || stat(pathprog
, &statbuf
))
1378 _cupsLangPrintf(stdout
,
1379 _(" WARN Missing cupsICCProfile "
1381 !attr
->value
|| !attr
->value
[0] ? "<NULL>" :
1391 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
1393 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
1395 if ((!attr
->value
|| stat(attr
->value
, &statbuf
)) && verbose
>= 0)
1396 _cupsLangPrintf(stdout
, _(" WARN Missing "
1397 "APDialogExtension file \"%s\"\n"),
1398 attr
->value
? attr
->value
: "<NULL>");
1405 for (attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
);
1407 attr
= ppdFindNextAttr(ppd
, "APPrinterIconPath", NULL
))
1409 if ((!attr
->value
|| stat(attr
->value
, &statbuf
)) && verbose
>= 0)
1410 _cupsLangPrintf(stdout
, _(" WARN Missing "
1411 "APPrinterIconPath file \"%s\"\n"),
1412 attr
->value
? attr
->value
: "<NULL>");
1414 #endif /* __APPLE__ */
1419 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1421 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1425 * Then list the options, if "-v" was provided...
1430 _cupsLangPrintf(stdout
,
1432 " language_level = %d\n"
1433 " color_device = %s\n"
1434 " variable_sizes = %s\n"
1435 " landscape = %d\n",
1436 ppd
->language_level
,
1437 ppd
->color_device
? "TRUE" : "FALSE",
1438 ppd
->variable_sizes
? "TRUE" : "FALSE",
1441 switch (ppd
->colorspace
)
1444 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1447 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1450 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1453 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1456 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1460 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1461 ppd
->num_emulations
);
1462 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1463 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1464 j
, ppd
->emulations
[j
].name
);
1466 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1467 ppd
->lang_encoding
);
1468 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1470 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1471 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1472 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1473 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1475 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1476 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1477 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1478 ppd
->shortnickname
);
1479 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1480 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1482 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1483 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1485 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1488 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1490 _cupsLangPrintf(stdout
,
1491 " options[%d] = %s (%s) %s %s %.0f "
1493 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1494 sections
[option
->section
], option
->order
,
1495 option
->num_choices
);
1497 if (!strcmp(option
->keyword
, "PageSize") ||
1498 !strcmp(option
->keyword
, "PageRegion"))
1500 for (m
= option
->num_choices
, choice
= option
->choices
;
1504 size
= ppdPageSize(ppd
, choice
->choice
);
1507 _cupsLangPrintf(stdout
,
1509 choice
->choice
, choice
->text
);
1511 _cupsLangPrintf(stdout
,
1512 " %s (%s) = %.2fx%.2fin "
1513 "(%.1f,%.1f,%.1f,%.1f)",
1514 choice
->choice
, choice
->text
,
1515 size
->width
/ 72.0, size
->length
/ 72.0,
1516 size
->left
/ 72.0, size
->bottom
/ 72.0,
1517 size
->right
/ 72.0, size
->top
/ 72.0);
1519 if (!strcmp(option
->defchoice
, choice
->choice
))
1520 _cupsLangPuts(stdout
, " *\n");
1522 _cupsLangPuts(stdout
, "\n");
1527 for (m
= option
->num_choices
, choice
= option
->choices
;
1531 _cupsLangPrintf(stdout
, " %s (%s)",
1532 choice
->choice
, choice
->text
);
1534 if (!strcmp(option
->defchoice
, choice
->choice
))
1535 _cupsLangPuts(stdout
, " *\n");
1537 _cupsLangPuts(stdout
, "\n");
1543 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1545 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1546 _cupsLangPrintf(stdout
,
1547 " profiles[%d] = %s/%s %.3f %.3f "
1548 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1549 j
, ppd
->profiles
[j
].resolution
,
1550 ppd
->profiles
[j
].media_type
,
1551 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1552 ppd
->profiles
[j
].matrix
[0][0],
1553 ppd
->profiles
[j
].matrix
[0][1],
1554 ppd
->profiles
[j
].matrix
[0][2],
1555 ppd
->profiles
[j
].matrix
[1][0],
1556 ppd
->profiles
[j
].matrix
[1][1],
1557 ppd
->profiles
[j
].matrix
[1][2],
1558 ppd
->profiles
[j
].matrix
[2][0],
1559 ppd
->profiles
[j
].matrix
[2][1],
1560 ppd
->profiles
[j
].matrix
[2][2]);
1562 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1563 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1564 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1567 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1568 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1569 _cupsLangPrintf(stdout
,
1570 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1571 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1572 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1573 ppd
->attrs
[j
]->text
,
1574 ppd
->attrs
[j
]->value
?
1575 ppd
->attrs
[j
]->value
: "(null)");
1589 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1593 check_basics(const char *filename
) /* I - PPD file to check */
1595 cups_file_t
*fp
; /* File pointer */
1596 int ch
; /* Current character */
1597 int col
, /* Current column */
1598 whitespace
; /* Only seen whitespace? */
1599 int eol
; /* Line endings */
1600 int linenum
; /* Line number */
1601 int mixed
; /* Mixed line endings? */
1604 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1613 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1615 if (ch
== '\r' || ch
== '\n')
1619 if (eol
== EOL_NONE
)
1621 else if (eol
!= EOL_LF
)
1624 else if (ch
== '\r')
1626 if (cupsFilePeekChar(fp
) == '\n')
1628 cupsFileGetChar(fp
);
1630 if (eol
== EOL_NONE
)
1635 else if (eol
== EOL_NONE
)
1641 if (col
> 0 && whitespace
)
1642 _cupsLangPrintf(stdout
,
1643 _(" WARN Line %d only contains whitespace!\n"),
1652 if (ch
!= ' ' && ch
!= '\t')
1660 _cupsLangPuts(stdout
,
1661 _(" WARN File contains a mix of CR, LF, and "
1662 "CR LF line endings!\n"));
1664 if (eol
== EOL_CRLF
)
1665 _cupsLangPuts(stdout
,
1666 _(" WARN Non-Windows PPD files should use lines "
1667 "ending with only LF, not CR LF!\n"));
1674 * 'check_constraints()' - Check UIConstraints in the PPD file.
1677 int /* O - Errors found */
1678 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1679 int errors
, /* I - Errors found */
1680 int verbose
, /* I - Verbosity level */
1681 int warn
) /* I - Warnings only? */
1683 int j
; /* Looping var */
1684 ppd_const_t
*c
; /* Current constraint */
1685 ppd_option_t
*option
; /* Standard UI option */
1686 ppd_option_t
*option2
; /* Standard UI option */
1687 const char *prefix
; /* WARN/FAIL prefix */
1690 prefix
= warn
? " WARN " : "**FAIL**";
1692 for (j
= ppd
->num_consts
, c
= ppd
->consts
; j
> 0; j
--, c
++)
1694 option
= ppdFindOption(ppd
, c
->option1
);
1695 option2
= ppdFindOption(ppd
, c
->option2
);
1697 if (!option
|| !option2
)
1699 if (!warn
&& !errors
&& !verbose
)
1700 _cupsLangPuts(stdout
, _(" FAIL\n"));
1703 _cupsLangPrintf(stdout
,
1704 _(" %s Missing option %s in "
1705 "UIConstraint \"*%s %s *%s %s\"!\n"),
1707 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1710 _cupsLangPrintf(stdout
,
1711 _(" %s Missing option %s in "
1712 "UIConstraint \"*%s %s *%s %s\"!\n"),
1714 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1722 if (c
->choice1
[0] && !ppdFindChoice(option
, c
->choice1
))
1724 if (!warn
&& !errors
&& !verbose
)
1725 _cupsLangPuts(stdout
, _(" FAIL\n"));
1727 _cupsLangPrintf(stdout
,
1728 _(" %s Missing choice *%s %s in "
1729 "UIConstraint \"*%s %s *%s %s\"!\n"),
1730 prefix
, c
->option1
, c
->choice1
,
1731 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1737 if (c
->choice2
[0] && !ppdFindChoice(option2
, c
->choice2
))
1739 if (!warn
&& !errors
&& !verbose
)
1740 _cupsLangPuts(stdout
, _(" FAIL\n"));
1742 _cupsLangPrintf(stdout
,
1743 _(" %s Missing choice *%s %s in "
1744 "UIConstraint \"*%s %s *%s %s\"!\n"),
1745 prefix
, c
->option2
, c
->choice2
,
1746 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1758 * 'check_defaults()' - Check default option keywords in the PPD file.
1761 int /* O - Errors found */
1762 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
1763 int errors
, /* I - Errors found */
1764 int verbose
, /* I - Verbosity level */
1765 int warn
) /* I - Warnings only? */
1767 int j
, k
; /* Looping vars */
1768 ppd_attr_t
*attr
; /* PPD attribute */
1769 ppd_option_t
*option
; /* Standard UI option */
1770 const char *prefix
; /* WARN/FAIL prefix */
1773 prefix
= warn
? " WARN " : "**FAIL**";
1775 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1777 attr
= ppd
->attrs
[j
];
1779 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1780 !strcmp(attr
->name
, "DefaultFont") ||
1781 !strcmp(attr
->name
, "DefaultImageableArea") ||
1782 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1783 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1784 !strcmp(attr
->name
, "DefaultResolution") ||
1785 !strcmp(attr
->name
, "DefaultTransfer"))
1788 if (!strncmp(attr
->name
, "Default", 7))
1790 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
1791 strcmp(attr
->value
, "Unknown"))
1794 * Check that the default option value matches a choice...
1797 for (k
= 0; k
< option
->num_choices
; k
++)
1798 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
1801 if (k
>= option
->num_choices
)
1803 if (!warn
&& !errors
&& !verbose
)
1804 _cupsLangPuts(stdout
, _(" FAIL\n"));
1807 _cupsLangPrintf(stdout
,
1808 _(" %s %s %s does not exist!\n"),
1809 prefix
, attr
->name
, attr
->value
);
1823 * 'check_filters()' - Check filters in the PPD file.
1826 int /* O - Errors found */
1827 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
1828 const char *root
, /* I - Root directory */
1829 int errors
, /* I - Errors found */
1830 int verbose
, /* I - Verbosity level */
1831 int warn
) /* I - Warnings only? */
1833 ppd_attr_t
*attr
; /* PPD attribute */
1834 const char *ptr
; /* Pointer into string */
1835 struct stat statbuf
; /* File information */
1836 char super
[16], /* Super-type for filter */
1837 type
[256], /* Type for filter */
1838 program
[256], /* Program/filter name */
1839 pathprog
[1024]; /* Complete path to program/filter */
1840 int cost
; /* Cost of filter */
1841 const char *prefix
; /* WARN/FAIL prefix */
1844 prefix
= warn
? " WARN " : "**FAIL**";
1846 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
1848 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
1851 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1854 if (!warn
&& !errors
&& !verbose
)
1855 _cupsLangPuts(stdout
, _(" FAIL\n"));
1858 _cupsLangPrintf(stdout
,
1859 _(" %s Bad cupsFilter value \"%s\"!\n"),
1860 prefix
, attr
->value
? attr
->value
: "");
1867 if (program
[0] == '/')
1868 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1871 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1872 ptr
= CUPS_SERVERBIN
;
1874 if (*ptr
== '/' || !*root
)
1875 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1878 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1882 if (stat(pathprog
, &statbuf
))
1884 if (!warn
&& !errors
&& !verbose
)
1885 _cupsLangPuts(stdout
, _(" FAIL\n"));
1888 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
1889 "file \"%s\"\n"), prefix
, program
);
1897 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
1899 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
1902 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1905 if (!warn
&& !errors
&& !verbose
)
1906 _cupsLangPuts(stdout
, _(" FAIL\n"));
1909 _cupsLangPrintf(stdout
,
1910 _(" %s Bad cupsPreFilter value \"%s\"!\n"),
1911 prefix
, attr
->value
? attr
->value
: "");
1918 if (program
[0] == '/')
1919 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1922 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1923 ptr
= CUPS_SERVERBIN
;
1925 if (*ptr
== '/' || !*root
)
1926 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1929 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1933 if (stat(pathprog
, &statbuf
))
1935 if (!warn
&& !errors
&& !verbose
)
1936 _cupsLangPuts(stdout
, _(" FAIL\n"));
1939 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
1940 "file \"%s\"\n"), prefix
, program
);
1953 * 'check_translations()' - Check translations in the PPD file.
1956 int /* O - Errors found */
1957 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
1958 int errors
, /* I - Errors found */
1959 int verbose
, /* I - Verbosity level */
1960 int warn
) /* I - Warnings only? */
1962 int j
; /* Looping var */
1963 ppd_attr_t
*attr
; /* PPD attribute */
1964 char *languages
, /* Copy of attribute value */
1965 *langstart
, /* Start of current language */
1966 *langptr
, /* Pointer into languages */
1967 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
1968 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
1969 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
1970 cllkeyword
[PPD_MAX_NAME
];
1971 /* Custom option keyword (base) */
1972 ppd_option_t
*option
; /* Standard UI option */
1973 ppd_coption_t
*coption
; /* Custom option */
1974 ppd_cparam_t
*cparam
; /* Custom parameter */
1975 cups_array_t
*langlist
; /* List of languages so far */
1976 char ll
[3]; /* Base language */
1977 const char *prefix
; /* WARN/FAIL prefix */
1980 prefix
= warn
? " WARN " : "**FAIL**";
1982 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1986 * This file contains localizations, check them...
1989 languages
= strdup(attr
->value
);
1990 langlist
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
1992 for (langptr
= languages
; *langptr
;)
1995 * Skip leading whitespace...
1998 while (isspace(*langptr
& 255))
2005 * Find the end of this language name...
2008 for (langstart
= langptr
;
2009 *langptr
&& !isspace(*langptr
& 255);
2015 j
= strlen(langstart
);
2016 if (j
!= 2 && j
!= 5)
2018 if (!warn
&& !errors
&& !verbose
)
2019 _cupsLangPuts(stdout
, _(" FAIL\n"));
2022 _cupsLangPrintf(stdout
,
2023 _(" %s Bad language \"%s\"!\n"),
2032 cupsArrayAdd(langlist
, langstart
);
2034 strlcpy(ll
, langstart
, sizeof(ll
));
2037 * Loop through all options and choices...
2040 for (option
= ppdFirstOption(ppd
);
2042 option
= ppdNextOption(ppd
))
2044 snprintf(keyword
, sizeof(keyword
), "%s.Translation", langstart
);
2045 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
2047 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
2048 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
2050 if (!warn
&& !errors
&& !verbose
)
2051 _cupsLangPuts(stdout
, _(" FAIL\n"));
2054 _cupsLangPrintf(stdout
,
2055 _(" %s Missing \"%s\" translation "
2056 "string for option %s!\n"),
2057 prefix
, langstart
, option
->keyword
);
2062 else if (!valid_utf8(attr
->text
))
2064 if (!warn
&& !errors
&& !verbose
)
2065 _cupsLangPuts(stdout
, _(" FAIL\n"));
2068 _cupsLangPrintf(stdout
,
2069 _(" %s Bad UTF-8 \"%s\" translation "
2070 "string for option %s!\n"),
2071 prefix
, langstart
, option
->keyword
);
2077 snprintf(keyword
, sizeof(keyword
), "%s.%s", langstart
,
2079 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
2082 for (j
= 0; j
< option
->num_choices
; j
++)
2084 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
2085 (coption
= ppdFindCustomOption(ppd
,
2086 option
->keyword
)) != NULL
)
2088 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
2089 langstart
, option
->keyword
);
2091 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
2092 !valid_utf8(attr
->text
))
2094 if (!warn
&& !errors
&& !verbose
)
2095 _cupsLangPuts(stdout
, _(" FAIL\n"));
2098 _cupsLangPrintf(stdout
,
2099 _(" %s Bad UTF-8 \"%s\" "
2100 "translation string for option %s, "
2103 ckeyword
+ 1 + strlen(langstart
),
2110 if (strcasecmp(option
->keyword
, "PageSize"))
2112 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
2114 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
2116 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
2117 langstart
, option
->keyword
);
2118 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
2119 ll
, option
->keyword
);
2121 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
2122 cparam
->name
)) == NULL
&&
2123 (attr
= ppdFindAttr(ppd
, cllkeyword
,
2124 cparam
->name
)) == NULL
)
2126 if (!warn
&& !errors
&& !verbose
)
2127 _cupsLangPuts(stdout
, _(" FAIL\n"));
2130 _cupsLangPrintf(stdout
,
2131 _(" %s Missing \"%s\" "
2132 "translation string for option %s, "
2135 ckeyword
+ 1 + strlen(langstart
),
2141 else if (!valid_utf8(attr
->text
))
2143 if (!warn
&& !errors
&& !verbose
)
2144 _cupsLangPuts(stdout
, _(" FAIL\n"));
2147 _cupsLangPrintf(stdout
,
2148 _(" %s Bad UTF-8 \"%s\" "
2149 "translation string for option %s, "
2152 ckeyword
+ 1 + strlen(langstart
),
2161 else if ((attr
= ppdFindAttr(ppd
, keyword
,
2162 option
->choices
[j
].choice
)) == NULL
&&
2163 (attr
= ppdFindAttr(ppd
, llkeyword
,
2164 option
->choices
[j
].choice
)) == NULL
)
2166 if (!warn
&& !errors
&& !verbose
)
2167 _cupsLangPuts(stdout
, _(" FAIL\n"));
2170 _cupsLangPrintf(stdout
,
2171 _(" %s Missing \"%s\" "
2172 "translation string for option %s, "
2174 prefix
, langstart
, option
->keyword
,
2175 option
->choices
[j
].choice
);
2180 else if (!valid_utf8(attr
->text
))
2182 if (!warn
&& !errors
&& !verbose
)
2183 _cupsLangPuts(stdout
, _(" FAIL\n"));
2186 _cupsLangPrintf(stdout
,
2187 _(" %s Bad UTF-8 \"%s\" "
2188 "translation string for option %s, "
2190 prefix
, langstart
, option
->keyword
,
2191 option
->choices
[j
].choice
);
2201 * Verify that we have the base language for each localized one...
2204 for (langptr
= (char *)cupsArrayFirst(langlist
);
2206 langptr
= (char *)cupsArrayNext(langlist
))
2210 * Lookup the base language...
2213 cupsArraySave(langlist
);
2215 strlcpy(ll
, langptr
, sizeof(ll
));
2217 if (!cupsArrayFind(langlist
, ll
) && strcmp(ll
, "zh"))
2219 if (!warn
&& !errors
&& !verbose
)
2220 _cupsLangPuts(stdout
, _(" FAIL\n"));
2223 _cupsLangPrintf(stdout
,
2224 _(" %s No base translation \"%s\" "
2225 "is included in file!\n"), prefix
, ll
);
2231 cupsArrayRestore(langlist
);
2235 * Free memory used for the languages...
2238 cupsArrayDelete(langlist
);
2247 * 'show_conflicts()' - Show option conflicts in a PPD file.
2251 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
2253 int i
, j
; /* Looping variables */
2254 ppd_const_t
*c
; /* Current constraint */
2255 ppd_option_t
*o1
, *o2
; /* Options */
2256 ppd_choice_t
*c1
, *c2
; /* Choices */
2260 * Loop through all of the UI constraints and report any options
2264 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
2267 * Grab pointers to the first option...
2270 o1
= ppdFindOption(ppd
, c
->option1
);
2274 else if (c
->choice1
[0] != '\0')
2277 * This constraint maps to a specific choice.
2280 c1
= ppdFindChoice(o1
, c
->choice1
);
2285 * This constraint applies to any choice for this option.
2288 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
2293 !strcasecmp(c1
->choice
, "None") ||
2294 !strcasecmp(c1
->choice
, "Off") ||
2295 !strcasecmp(c1
->choice
, "False"))
2300 * Grab pointers to the second option...
2303 o2
= ppdFindOption(ppd
, c
->option2
);
2307 else if (c
->choice2
[0] != '\0')
2310 * This constraint maps to a specific choice.
2313 c2
= ppdFindChoice(o2
, c
->choice2
);
2318 * This constraint applies to any choice for this option.
2321 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
2326 !strcasecmp(c2
->choice
, "None") ||
2327 !strcasecmp(c2
->choice
, "Off") ||
2328 !strcasecmp(c2
->choice
, "False"))
2333 * If both options are marked then there is a conflict...
2336 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
2337 _cupsLangPrintf(stdout
,
2338 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
2339 " (constraint=\"%s %s %s %s\")\n"),
2340 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
2341 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2347 * 'usage()' - Show program usage...
2353 _cupsLangPuts(stdout
,
2354 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
2355 "[... filenameN.ppd[.gz]]\n"
2356 " program | cupstestppd [options] -\n"
2360 " -R root-directory Set alternate root\n"
2361 " -W {all,none,constraints,defaults,filters,translations}\n"
2362 " Issue warnings instead of errors\n"
2363 " -q Run silently\n"
2364 " -r Use 'relaxed' open mode\n"
2365 " -v Be slightly verbose\n"
2366 " -vv Be very verbose\n"));
2373 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
2376 int /* O - 1 if valid, 0 if not */
2377 valid_utf8(const char *s
) /* I - String to check */
2384 * Check for valid UTF-8 sequence...
2387 if ((*s
& 0xc0) == 0x80)
2388 return (0); /* Illegal suffix byte */
2389 else if ((*s
& 0xe0) == 0xc0)
2392 * 2-byte sequence...
2397 if ((*s
& 0xc0) != 0x80)
2398 return (0); /* Missing suffix byte */
2400 else if ((*s
& 0xf0) == 0xe0)
2403 * 3-byte sequence...
2408 if ((*s
& 0xc0) != 0x80)
2409 return (0); /* Missing suffix byte */
2413 if ((*s
& 0xc0) != 0x80)
2414 return (0); /* Missing suffix byte */
2416 else if ((*s
& 0xf8) == 0xf0)
2419 * 4-byte sequence...
2424 if ((*s
& 0xc0) != 0x80)
2425 return (0); /* Missing suffix byte */
2429 if ((*s
& 0xc0) != 0x80)
2430 return (0); /* Missing suffix byte */
2434 if ((*s
& 0xc0) != 0x80)
2435 return (0); /* Missing suffix byte */
2438 return (0); /* Bad sequence */
2449 * End of "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $".