2 * "$Id: cupstestppd.c 6533 2007-05-15 15:54:23Z 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 static void check_basics(const char *filename
);
95 static int check_constraints(ppd_file_t
*ppd
, int errors
, int verbose
,
97 static int check_defaults(ppd_file_t
*ppd
, int errors
, int verbose
,
99 static int check_filters(ppd_file_t
*ppd
, const char *root
, int errors
,
100 int verbose
, int warn
);
101 static int check_translations(ppd_file_t
*ppd
, int errors
, int verbose
,\
103 static void show_conflicts(ppd_file_t
*ppd
);
104 static void usage(void);
105 static int valid_utf8(const char *s
);
109 * 'main()' - Main entry for test program.
112 int /* O - Exit status */
113 main(int argc
, /* I - Number of command-line args */
114 char *argv
[]) /* I - Command-line arguments */
116 int i
, j
, k
, m
, n
; /* Looping vars */
117 int len
; /* Length of option name */
118 char *opt
; /* Option character */
119 const char *ptr
; /* Pointer into string */
120 int files
; /* Number of files */
121 int verbose
; /* Want verbose output? */
122 int warn
; /* Which errors to just warn about */
123 int status
; /* Exit status */
124 int errors
; /* Number of conformance errors */
125 int ppdversion
; /* PPD spec version in PPD file */
126 ppd_status_t error
; /* Status of ppdOpen*() */
127 int line
; /* Line number for error */
128 struct stat statbuf
; /* File information */
129 char pathprog
[1024], /* Complete path to program/filter */
130 *root
; /* Root directory */
131 int xdpi
, /* X resolution */
132 ydpi
; /* Y resolution */
133 ppd_file_t
*ppd
; /* PPD file record */
134 ppd_attr_t
*attr
; /* PPD attribute */
135 ppd_size_t
*size
; /* Size record */
136 ppd_group_t
*group
; /* UI group */
137 ppd_option_t
*option
; /* Standard UI option */
138 ppd_group_t
*group2
; /* UI group */
139 ppd_option_t
*option2
; /* Standard UI option */
140 ppd_choice_t
*choice
; /* Standard UI option choice */
141 static char *uis
[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
142 static char *sections
[] = { "ANY", "DOCUMENT", "EXIT",
143 "JCL", "PAGE", "PROLOG" };
146 _cupsSetLocale(argv
);
149 * Display PPD files for each file listed on the command-line...
152 ppdSetConformance(PPD_CONFORM_STRICT
);
161 for (i
= 1; i
< argc
; i
++)
162 if (argv
[i
][0] == '-' && argv
[i
][1])
164 for (opt
= argv
[i
] + 1; *opt
; opt
++)
167 case 'R' : /* Alternate root directory */
176 case 'W' : /* Turn errors into warnings */
182 if (!strcmp(argv
[i
], "none"))
184 else if (!strcmp(argv
[i
], "constraints"))
185 warn
|= WARN_CONSTRAINTS
;
186 else if (!strcmp(argv
[i
], "defaults"))
187 warn
|= WARN_DEFAULTS
;
188 else if (!strcmp(argv
[i
], "filters"))
189 warn
|= WARN_FILTERS
;
190 else if (!strcmp(argv
[i
], "translations"))
191 warn
|= WARN_TRANSLATIONS
;
192 else if (!strcmp(argv
[i
], "all"))
198 case 'q' : /* Quiet mode */
201 _cupsLangPuts(stderr
,
202 _("cupstestppd: The -q option is incompatible "
203 "with the -v option.\n"));
210 case 'r' : /* Relaxed mode */
211 ppdSetConformance(PPD_CONFORM_RELAXED
);
214 case 'v' : /* Verbose mode */
217 _cupsLangPuts(stderr
,
218 _("cupstestppd: The -v option is incompatible "
219 "with the -q option.\n"));
234 * Open the PPD file...
237 if (files
&& verbose
>= 0)
238 _cupsLangPuts(stdout
, "\n");
242 if (argv
[i
][0] == '-')
251 ppd
= ppdOpen(stdin
);
256 * Read from a file...
260 printf("%s:", argv
[i
]);
262 ppd
= ppdOpenFile(argv
[i
]);
267 error
= ppdLastError(&line
);
269 if (error
<= PPD_ALLOC_ERROR
)
271 status
= ERROR_FILE_OPEN
;
274 _cupsLangPrintf(stdout
,
276 " **FAIL** Unable to open PPD file - %s\n"),
281 status
= ERROR_PPD_FORMAT
;
285 _cupsLangPrintf(stdout
,
287 " **FAIL** Unable to open PPD file - "
289 ppdErrorString(error
), line
);
293 case PPD_MISSING_PPDADOBE4
:
294 _cupsLangPuts(stdout
,
295 _(" REF: Page 42, section 5.2.\n"));
297 case PPD_MISSING_VALUE
:
298 _cupsLangPuts(stdout
,
299 _(" REF: Page 20, section 3.4.\n"));
301 case PPD_BAD_OPEN_GROUP
:
302 case PPD_NESTED_OPEN_GROUP
:
303 _cupsLangPuts(stdout
,
304 _(" REF: Pages 45-46, section 5.2.\n"));
306 case PPD_BAD_OPEN_UI
:
307 case PPD_NESTED_OPEN_UI
:
308 _cupsLangPuts(stdout
,
309 _(" REF: Pages 42-45, section 5.2.\n"));
311 case PPD_BAD_ORDER_DEPENDENCY
:
312 _cupsLangPuts(stdout
,
313 _(" REF: Pages 48-49, section 5.2.\n"));
315 case PPD_BAD_UI_CONSTRAINTS
:
316 _cupsLangPuts(stdout
,
317 _(" REF: Pages 52-54, section 5.2.\n"));
319 case PPD_MISSING_ASTERISK
:
320 _cupsLangPuts(stdout
,
321 _(" REF: Page 15, section 3.2.\n"));
323 case PPD_LINE_TOO_LONG
:
324 _cupsLangPuts(stdout
,
325 _(" REF: Page 15, section 3.1.\n"));
327 case PPD_ILLEGAL_CHARACTER
:
328 _cupsLangPuts(stdout
,
329 _(" REF: Page 15, section 3.1.\n"));
331 case PPD_ILLEGAL_MAIN_KEYWORD
:
332 _cupsLangPuts(stdout
,
333 _(" REF: Pages 16-17, section 3.2.\n"));
335 case PPD_ILLEGAL_OPTION_KEYWORD
:
336 _cupsLangPuts(stdout
,
337 _(" REF: Page 19, section 3.3.\n"));
339 case PPD_ILLEGAL_TRANSLATION
:
340 _cupsLangPuts(stdout
,
341 _(" REF: Page 27, section 3.5.\n"));
347 check_basics(argv
[i
]);
355 * Show the header and then perform basic conformance tests (limited
356 * only by what the CUPS PPD functions actually load...)
363 _cupsLangPuts(stdout
,
364 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
366 if ((attr
= ppdFindAttr(ppd
, "FormatVersion", NULL
)) != NULL
&&
368 ppdversion
= (int)(10 * atof(attr
->value
) + 0.5);
371 * Look for default keywords with no matching option...
374 if (!(warn
& WARN_DEFAULTS
))
375 errors
= check_defaults(ppd
, errors
, verbose
, 0);
377 if ((attr
= ppdFindAttr(ppd
, "DefaultImageableArea", NULL
)) == NULL
)
381 if (!errors
&& !verbose
)
382 _cupsLangPuts(stdout
, _(" FAIL\n"));
384 _cupsLangPuts(stdout
,
385 _(" **FAIL** REQUIRED DefaultImageableArea\n"
386 " REF: Page 102, section 5.15.\n"));
391 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
392 strcmp(attr
->value
, "Unknown"))
396 if (!errors
&& !verbose
)
397 _cupsLangPuts(stdout
, _(" FAIL\n"));
399 _cupsLangPrintf(stdout
,
400 _(" **FAIL** BAD DefaultImageableArea %s!\n"
401 " REF: Page 102, section 5.15.\n"),
410 _cupsLangPuts(stdout
, _(" PASS DefaultImageableArea\n"));
413 if ((attr
= ppdFindAttr(ppd
, "DefaultPaperDimension", NULL
)) == NULL
)
417 if (!errors
&& !verbose
)
418 _cupsLangPuts(stdout
, _(" FAIL\n"));
420 _cupsLangPuts(stdout
,
421 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
422 " REF: Page 103, section 5.15.\n"));
427 else if (ppdPageSize(ppd
, attr
->value
) == NULL
&&
428 strcmp(attr
->value
, "Unknown"))
432 if (!errors
&& !verbose
)
433 _cupsLangPuts(stdout
, _(" FAIL\n"));
435 _cupsLangPrintf(stdout
,
436 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
437 " REF: Page 103, section 5.15.\n"),
443 else if (verbose
> 0)
444 _cupsLangPuts(stdout
, _(" PASS DefaultPaperDimension\n"));
446 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
447 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
450 * Verify that we have a default choice...
453 if (option
->defchoice
[0])
455 if (ppdFindChoice(option
, option
->defchoice
) == NULL
&&
456 strcmp(option
->defchoice
, "Unknown"))
460 if (!errors
&& !verbose
)
461 _cupsLangPuts(stdout
, _(" FAIL\n"));
463 _cupsLangPrintf(stdout
,
464 _(" **FAIL** BAD Default%s %s\n"
465 " REF: Page 40, section 4.5.\n"),
466 option
->keyword
, option
->defchoice
);
471 else if (verbose
> 0)
472 _cupsLangPrintf(stdout
,
473 _(" PASS Default%s\n"),
480 if (!errors
&& !verbose
)
481 _cupsLangPuts(stdout
, _(" FAIL\n"));
483 _cupsLangPrintf(stdout
,
484 _(" **FAIL** REQUIRED Default%s\n"
485 " REF: Page 40, section 4.5.\n"),
493 if (ppdFindAttr(ppd
, "FileVersion", NULL
) != NULL
)
496 _cupsLangPuts(stdout
, _(" PASS FileVersion\n"));
502 if (!errors
&& !verbose
)
503 _cupsLangPuts(stdout
, _(" FAIL\n"));
505 _cupsLangPuts(stdout
,
506 _(" **FAIL** REQUIRED FileVersion\n"
507 " REF: Page 56, section 5.3.\n"));
513 if (ppdFindAttr(ppd
, "FormatVersion", NULL
) != NULL
)
516 _cupsLangPuts(stdout
, _(" PASS FormatVersion\n"));
522 if (!errors
&& !verbose
)
523 _cupsLangPuts(stdout
, _(" FAIL\n"));
525 _cupsLangPuts(stdout
,
526 _(" **FAIL** REQUIRED FormatVersion\n"
527 " REF: Page 56, section 5.3.\n"));
533 if (ppd
->lang_encoding
!= NULL
)
536 _cupsLangPuts(stdout
, _(" PASS LanguageEncoding\n"));
538 else if (ppdversion
> 40)
542 if (!errors
&& !verbose
)
543 _cupsLangPuts(stdout
, _(" FAIL\n"));
545 _cupsLangPuts(stdout
,
546 _(" **FAIL** REQUIRED LanguageEncoding\n"
547 " REF: Pages 56-57, section 5.3.\n"));
553 if (ppd
->lang_version
!= NULL
)
556 _cupsLangPuts(stdout
, _(" PASS LanguageVersion\n"));
562 if (!errors
&& !verbose
)
563 _cupsLangPuts(stdout
, _(" FAIL\n"));
565 _cupsLangPuts(stdout
,
566 _(" **FAIL** REQUIRED LanguageVersion\n"
567 " REF: Pages 57-58, section 5.3.\n"));
573 if (ppd
->manufacturer
!= NULL
)
575 if (!strncasecmp(ppd
->manufacturer
, "Hewlett-Packard", 15) ||
576 !strncasecmp(ppd
->manufacturer
, "Hewlett Packard", 15))
580 if (!errors
&& !verbose
)
581 _cupsLangPuts(stdout
, _(" FAIL\n"));
583 _cupsLangPuts(stdout
,
584 _(" **FAIL** BAD Manufacturer (should be "
586 " REF: Page 211, table D.1.\n"));
591 else if (!strncasecmp(ppd
->manufacturer
, "OkiData", 7) ||
592 !strncasecmp(ppd
->manufacturer
, "Oki Data", 8))
596 if (!errors
&& !verbose
)
597 _cupsLangPuts(stdout
, _(" FAIL\n"));
599 _cupsLangPuts(stdout
,
600 _(" **FAIL** BAD Manufacturer (should be "
602 " REF: Page 211, table D.1.\n"));
607 else if (verbose
> 0)
608 _cupsLangPuts(stdout
, _(" PASS Manufacturer\n"));
610 else if (ppdversion
>= 43)
614 if (!errors
&& !verbose
)
615 _cupsLangPuts(stdout
, _(" FAIL\n"));
617 _cupsLangPuts(stdout
,
618 _(" **FAIL** REQUIRED Manufacturer\n"
619 " REF: Pages 58-59, section 5.3.\n"));
625 if (ppd
->modelname
!= NULL
)
627 for (ptr
= ppd
->modelname
; *ptr
; ptr
++)
628 if (!isalnum(*ptr
& 255) && !strchr(" ./-+", *ptr
))
635 if (!errors
&& !verbose
)
636 _cupsLangPuts(stdout
, _(" FAIL\n"));
638 _cupsLangPrintf(stdout
,
639 _(" **FAIL** BAD ModelName - \"%c\" not "
640 "allowed in string.\n"
641 " REF: Pages 59-60, section 5.3.\n"),
647 else if (verbose
> 0)
648 _cupsLangPuts(stdout
, _(" PASS ModelName\n"));
654 if (!errors
&& !verbose
)
655 _cupsLangPuts(stdout
, _(" FAIL\n"));
657 _cupsLangPuts(stdout
,
658 _(" **FAIL** REQUIRED ModelName\n"
659 " REF: Pages 59-60, section 5.3.\n"));
665 if (ppd
->nickname
!= NULL
)
668 _cupsLangPuts(stdout
, _(" PASS NickName\n"));
674 if (!errors
&& !verbose
)
675 _cupsLangPuts(stdout
, _(" FAIL\n"));
677 _cupsLangPuts(stdout
,
678 _(" **FAIL** REQUIRED NickName\n"
679 " REF: Page 60, section 5.3.\n"));
685 if (ppdFindOption(ppd
, "PageSize") != NULL
)
688 _cupsLangPuts(stdout
, _(" PASS PageSize\n"));
694 if (!errors
&& !verbose
)
695 _cupsLangPuts(stdout
, _(" FAIL\n"));
697 _cupsLangPuts(stdout
,
698 _(" **FAIL** REQUIRED PageSize\n"
699 " REF: Pages 99-100, section 5.14.\n"));
705 if (ppdFindOption(ppd
, "PageRegion") != NULL
)
708 _cupsLangPuts(stdout
, _(" PASS PageRegion\n"));
714 if (!errors
&& !verbose
)
715 _cupsLangPuts(stdout
, _(" FAIL\n"));
717 _cupsLangPuts(stdout
,
718 _(" **FAIL** REQUIRED PageRegion\n"
719 " REF: Page 100, section 5.14.\n"));
725 if (ppd
->pcfilename
!= NULL
)
728 _cupsLangPuts(stdout
, _(" PASS PCFileName\n"));
734 if (!errors
&& !verbose
)
735 _cupsLangPuts(stdout
, _(" FAIL\n"));
737 _cupsLangPuts(stdout
,
738 _(" **FAIL** REQUIRED PCFileName\n"
739 " REF: Pages 61-62, section 5.3.\n"));
745 if (ppd
->product
!= NULL
)
747 if (ppd
->product
[0] != '(' ||
748 ppd
->product
[strlen(ppd
->product
) - 1] != ')')
752 if (!errors
&& !verbose
)
753 _cupsLangPuts(stdout
, _(" FAIL\n"));
755 _cupsLangPuts(stdout
,
756 _(" **FAIL** BAD Product - not \"(string)\".\n"
757 " REF: Page 62, section 5.3.\n"));
762 else if (verbose
> 0)
763 _cupsLangPuts(stdout
, _(" PASS Product\n"));
769 if (!errors
&& !verbose
)
770 _cupsLangPuts(stdout
, _(" FAIL\n"));
772 _cupsLangPuts(stdout
,
773 _(" **FAIL** REQUIRED Product\n"
774 " REF: Page 62, section 5.3.\n"));
780 if ((attr
= ppdFindAttr(ppd
, "PSVersion", NULL
)) != NULL
&&
783 char junkstr
[255]; /* Temp string */
784 int junkint
; /* Temp integer */
787 if (sscanf(attr
->value
, "(%[^)])%d", junkstr
, &junkint
) != 2)
791 if (!errors
&& !verbose
)
792 _cupsLangPuts(stdout
, _(" FAIL\n"));
794 _cupsLangPuts(stdout
,
795 _(" **FAIL** BAD PSVersion - not \"(string) "
797 " REF: Pages 62-64, section 5.3.\n"));
802 else if (verbose
> 0)
803 _cupsLangPuts(stdout
, _(" PASS PSVersion\n"));
809 if (!errors
&& !verbose
)
810 _cupsLangPuts(stdout
, _(" FAIL\n"));
812 _cupsLangPuts(stdout
,
813 _(" **FAIL** REQUIRED PSVersion\n"
814 " REF: Pages 62-64, section 5.3.\n"));
820 if (ppd
->shortnickname
!= NULL
)
822 if (strlen(ppd
->shortnickname
) > 31)
826 if (!errors
&& !verbose
)
827 _cupsLangPuts(stdout
, _(" FAIL\n"));
829 _cupsLangPuts(stdout
,
830 _(" **FAIL** BAD ShortNickName - longer "
832 " REF: Pages 64-65, section 5.3.\n"));
837 else if (verbose
> 0)
838 _cupsLangPuts(stdout
, _(" PASS ShortNickName\n"));
840 else if (ppdversion
>= 43)
844 if (!errors
&& !verbose
)
845 _cupsLangPuts(stdout
, _(" FAIL\n"));
847 _cupsLangPuts(stdout
,
848 _(" **FAIL** REQUIRED ShortNickName\n"
849 " REF: Page 64-65, section 5.3.\n"));
855 if (ppd
->patches
!= NULL
&& strchr(ppd
->patches
, '\"') &&
856 strstr(ppd
->patches
, "*End"))
860 if (!errors
&& !verbose
)
861 _cupsLangPuts(stdout
, _(" FAIL\n"));
863 _cupsLangPuts(stdout
,
864 _(" **FAIL** BAD JobPatchFile attribute in file\n"
865 " REF: Page 24, section 3.4.\n"));
872 * Check for page sizes without the corresponding ImageableArea or
873 * PaperDimension values...
876 if (ppd
->num_sizes
== 0)
880 if (!errors
&& !verbose
)
881 _cupsLangPuts(stdout
, _(" FAIL\n"));
883 _cupsLangPuts(stdout
,
884 _(" **FAIL** REQUIRED PageSize\n"
885 " REF: Page 41, section 5.\n"
886 " REF: Page 99, section 5.14.\n"));
893 for (j
= 0, size
= ppd
->sizes
; j
< ppd
->num_sizes
; j
++, size
++)
896 * Don't check custom size...
899 if (!strcmp(size
->name
, "Custom"))
903 * Check for ImageableArea...
906 if (size
->left
== 0.0 && size
->bottom
== 0.0 &&
907 size
->right
== 0.0 && size
->top
== 0.0)
911 if (!errors
&& !verbose
)
912 _cupsLangPuts(stdout
, _(" FAIL\n"));
914 _cupsLangPrintf(stdout
,
915 _(" **FAIL** REQUIRED ImageableArea for "
917 " REF: Page 41, section 5.\n"
918 " REF: Page 102, section 5.15.\n"),
926 * Check for PaperDimension...
929 if (size
->width
== 0.0 && size
->length
== 0.0)
933 if (!errors
&& !verbose
)
934 _cupsLangPuts(stdout
, _(" FAIL\n"));
936 _cupsLangPrintf(stdout
,
937 _(" **FAIL** REQUIRED PaperDimension "
939 " REF: Page 41, section 5.\n"
940 " REF: Page 103, section 5.15.\n"),
950 * Check for valid Resolution, JCLResolution, or SetResolution values...
953 if ((option
= ppdFindOption(ppd
, "Resolution")) == NULL
)
954 if ((option
= ppdFindOption(ppd
, "JCLResolution")) == NULL
)
955 option
= ppdFindOption(ppd
, "SetResolution");
959 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
962 * Verify that all resolution options are of the form NNNdpi
966 xdpi
= strtol(choice
->choice
, (char **)&ptr
, 10);
967 if (ptr
> choice
->choice
&& xdpi
> 0)
970 ydpi
= strtol(ptr
+ 1, (char **)&ptr
, 10);
977 if (xdpi
<= 0 || ydpi
<= 0 || strcmp(ptr
, "dpi"))
981 if (!errors
&& !verbose
)
982 _cupsLangPuts(stdout
, _(" FAIL\n"));
984 _cupsLangPrintf(stdout
,
985 _(" **FAIL** Bad %s choice %s!\n"
986 " REF: Page 84, section 5.9\n"),
987 option
->keyword
, choice
->choice
);
996 * Check for a duplex option, and for standard values...
999 if ((option
= ppdFindOption(ppd
, "Duplex")) == NULL
)
1000 if ((option
= ppdFindOption(ppd
, "JCLDuplex")) == NULL
)
1001 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1002 option
= ppdFindOption(ppd
, "KD03Duplex");
1006 if (ppdFindChoice(option
, "None") == NULL
)
1010 if (!errors
&& !verbose
)
1011 _cupsLangPuts(stdout
, _(" FAIL\n"));
1013 _cupsLangPrintf(stdout
,
1014 _(" **FAIL** REQUIRED %s does not define "
1016 " REF: Page 122, section 5.17\n"),
1023 for (j
= option
->num_choices
, choice
= option
->choices
; j
> 0; j
--, choice
++)
1024 if (strcmp(choice
->choice
, "None") &&
1025 strcmp(choice
->choice
, "DuplexNoTumble") &&
1026 strcmp(choice
->choice
, "DuplexTumble") &&
1027 strcmp(choice
->choice
, "SimplexTumble"))
1031 if (!errors
&& !verbose
)
1032 _cupsLangPuts(stdout
, _(" FAIL\n"));
1034 _cupsLangPrintf(stdout
,
1035 _(" **FAIL** Bad %s choice %s!\n"
1036 " REF: Page 122, section 5.17\n"),
1037 option
->keyword
, choice
->choice
);
1044 if ((attr
= ppdFindAttr(ppd
, "1284DeviceID", NULL
)) &&
1045 strcmp(attr
->name
, "1284DeviceID"))
1049 if (!errors
&& !verbose
)
1050 _cupsLangPuts(stdout
, _(" FAIL\n"));
1052 _cupsLangPrintf(stdout
,
1053 _(" **FAIL** %s must be 1284DeviceID!\n"
1054 " REF: Page 72, section 5.5\n"),
1061 if (!(warn
& WARN_CONSTRAINTS
))
1062 errors
= check_constraints(ppd
, errors
, verbose
, 0);
1064 if (!(warn
& WARN_FILTERS
))
1065 errors
= check_filters(ppd
, root
, errors
, verbose
, 0);
1067 if (!(warn
& WARN_TRANSLATIONS
))
1068 errors
= check_translations(ppd
, errors
, verbose
, 0);
1070 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1074 * This file contains localizations, check for conformance of the
1075 * base translation...
1078 if ((attr
= ppdFindAttr(ppd
, "LanguageEncoding", NULL
)) != NULL
)
1080 if (!attr
->value
|| strcmp(attr
->value
, "ISOLatin1"))
1082 if (!errors
&& !verbose
)
1083 _cupsLangPuts(stdout
, _(" FAIL\n"));
1086 _cupsLangPrintf(stderr
,
1087 _(" **FAIL** Bad LanguageEncoding %s - "
1088 "must be ISOLatin1!\n"),
1089 attr
->value
? attr
->value
: "(null)");
1094 if (!ppd
->lang_version
|| strcmp(ppd
->lang_version
, "English"))
1096 if (!errors
&& !verbose
)
1097 _cupsLangPuts(stdout
, _(" FAIL\n"));
1100 _cupsLangPrintf(stderr
,
1101 _(" **FAIL** Bad LanguageVersion %s - "
1102 "must be English!\n"),
1103 ppd
->lang_version
? ppd
->lang_version
: "(null)");
1109 * Loop through all options and choices...
1112 for (option
= ppdFirstOption(ppd
);
1114 option
= ppdNextOption(ppd
))
1117 * Check for special characters outside A0 to BF, F7, or F8
1118 * that are used for languages other than English.
1121 for (ptr
= option
->text
; *ptr
; ptr
++)
1122 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1123 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1128 if (!errors
&& !verbose
)
1129 _cupsLangPuts(stdout
, _(" FAIL\n"));
1132 _cupsLangPrintf(stdout
,
1133 _(" **FAIL** Default translation "
1134 "string for option %s contains 8-bit "
1141 for (j
= 0; j
< option
->num_choices
; j
++)
1144 * Check for special characters outside A0 to BF, F7, or F8
1145 * that are used for languages other than English.
1148 for (ptr
= option
->choices
[j
].text
; *ptr
; ptr
++)
1149 if ((*ptr
& 0x80) && (*ptr
& 0xe0) != 0xa0 &&
1150 (*ptr
& 0xff) != 0xf7 && (*ptr
& 0xff) != 0xf8)
1155 if (!errors
&& !verbose
)
1156 _cupsLangPuts(stdout
, _(" FAIL\n"));
1159 _cupsLangPrintf(stdout
,
1160 _(" **FAIL** Default translation "
1161 "string for option %s choice %s contains "
1162 "8-bit characters!\n"),
1164 option
->choices
[j
].choice
);
1174 * Final pass/fail notification...
1178 status
= ERROR_CONFORMANCE
;
1180 _cupsLangPuts(stdout
, _(" PASS\n"));
1184 check_basics(argv
[i
]);
1186 if (warn
& WARN_CONSTRAINTS
)
1187 errors
= check_constraints(ppd
, errors
, verbose
, 1);
1189 if (warn
& WARN_DEFAULTS
)
1190 errors
= check_defaults(ppd
, errors
, verbose
, 1);
1192 if (warn
& WARN_FILTERS
)
1193 errors
= check_filters(ppd
, root
, errors
, verbose
, 1);
1195 if (warn
& WARN_TRANSLATIONS
)
1196 errors
= check_translations(ppd
, errors
, verbose
, 1);
1199 * Look for default keywords with no corresponding option...
1202 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1204 attr
= ppd
->attrs
[j
];
1206 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1207 !strcmp(attr
->name
, "DefaultColorSep") ||
1208 !strcmp(attr
->name
, "DefaultFont") ||
1209 !strcmp(attr
->name
, "DefaultImageableArea") ||
1210 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1211 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1212 !strcmp(attr
->name
, "DefaultScreenProc") ||
1213 !strcmp(attr
->name
, "DefaultTransfer"))
1216 if (!strncmp(attr
->name
, "Default", 7) &&
1217 !ppdFindOption(ppd
, attr
->name
+ 7))
1218 _cupsLangPrintf(stdout
,
1219 _(" WARN %s has no corresponding "
1225 * Check for old Duplex option names...
1228 if ((option
= ppdFindOption(ppd
, "EFDuplex")) == NULL
)
1229 option
= ppdFindOption(ppd
, "KD03Duplex");
1233 _cupsLangPrintf(stdout
,
1234 _(" WARN Duplex option keyword %s "
1235 "should be named Duplex or JCLDuplex!\n"
1236 " REF: Page 122, section 5.17\n"),
1240 ppdMarkDefaults(ppd
);
1241 if (ppdConflicts(ppd
))
1243 _cupsLangPuts(stdout
,
1244 _(" WARN Default choices conflicting!\n"));
1246 show_conflicts(ppd
);
1249 if (ppdversion
< 43)
1251 _cupsLangPrintf(stdout
,
1252 _(" WARN Obsolete PPD version %.1f!\n"
1253 " REF: Page 42, section 5.2.\n"),
1257 if (!ppd
->lang_encoding
&& ppdversion
< 41)
1259 _cupsLangPuts(stdout
,
1260 _(" WARN LanguageEncoding required by PPD "
1262 " REF: Pages 56-57, section 5.3.\n"));
1265 if (!ppd
->manufacturer
&& ppdversion
< 43)
1267 _cupsLangPuts(stdout
,
1268 _(" WARN Manufacturer required by PPD "
1270 " REF: Pages 58-59, section 5.3.\n"));
1274 * Treat a PCFileName attribute longer than 12 characters as
1275 * a warning and not a hard error...
1278 if (ppd
->pcfilename
&& strlen(ppd
->pcfilename
) > 12)
1280 _cupsLangPuts(stdout
,
1281 _(" WARN PCFileName longer than 8.3 in "
1282 "violation of PPD spec.\n"
1283 " REF: Pages 61-62, section 5.3.\n"));
1286 if (!ppd
->shortnickname
&& ppdversion
< 43)
1288 _cupsLangPuts(stdout
,
1289 _(" WARN ShortNickName required by PPD "
1291 " REF: Pages 64-65, section 5.3.\n"));
1295 * Check the Protocols line and flag PJL + BCP since TBCP is
1296 * usually used with PJL...
1301 if (strstr(ppd
->protocols
, "PJL") &&
1302 strstr(ppd
->protocols
, "BCP") &&
1303 !strstr(ppd
->protocols
, "TBCP"))
1305 _cupsLangPuts(stdout
,
1306 _(" WARN Protocols contains both PJL "
1307 "and BCP; expected TBCP.\n"
1308 " REF: Pages 78-79, section 5.7.\n"));
1311 if (strstr(ppd
->protocols
, "PJL") &&
1312 (!ppd
->jcl_begin
|| !ppd
->jcl_end
|| !ppd
->jcl_ps
))
1314 _cupsLangPuts(stdout
,
1315 _(" WARN Protocols contains PJL but JCL "
1316 "attributes are not set.\n"
1317 " REF: Pages 78-79, section 5.7.\n"));
1322 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1323 * which are errors according to the spec but won't cause problems
1324 * with CUPS specifically...
1327 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1328 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1330 len
= strlen(option
->keyword
);
1332 for (m
= 0, group2
= ppd
->groups
;
1333 m
< ppd
->num_groups
;
1335 for (n
= 0, option2
= group2
->options
;
1336 n
< group2
->num_options
;
1338 if (option
!= option2
&&
1339 len
< strlen(option2
->keyword
) &&
1340 !strncmp(option
->keyword
, option2
->keyword
, len
))
1342 _cupsLangPrintf(stdout
,
1343 _(" WARN %s shares a common "
1345 " REF: Page 15, section "
1347 option
->keyword
, option2
->keyword
);
1356 for (attr
= ppdFindAttr(ppd
, "cupsICCProfile", NULL
);
1358 attr
= ppdFindNextAttr(ppd
, "cupsICCProfile", NULL
))
1362 if (attr
->value
[0] == '/')
1363 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, attr
->value
);
1366 if ((ptr
= getenv("CUPS_DATADIR")) == NULL
)
1369 if (*ptr
== '/' || !*root
)
1370 snprintf(pathprog
, sizeof(pathprog
), "%s%s/profiles/%s", root
,
1373 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/profiles/%s", root
,
1378 if (!attr
->value
|| !attr
->value
[0] || stat(pathprog
, &statbuf
))
1381 _cupsLangPrintf(stdout
,
1382 _(" WARN Missing cupsICCProfile "
1384 !attr
->value
|| !attr
->value
[0] ? "<NULL>" :
1394 for (attr
= ppdFindAttr(ppd
, "APDialogExtension", NULL
);
1396 attr
= ppdFindNextAttr(ppd
, "APDialogExtension", NULL
))
1398 if ((!attr
->value
|| stat(attr
->value
, &statbuf
)) && verbose
>= 0)
1399 _cupsLangPrintf(stdout
, _(" WARN Missing "
1400 "APDialogExtension file \"%s\"\n"),
1401 attr
->value
? attr
->value
: "<NULL>");
1408 for (attr
= ppdFindAttr(ppd
, "APPrinterIconPath", NULL
);
1410 attr
= ppdFindNextAttr(ppd
, "APPrinterIconPath", NULL
))
1412 if ((!attr
->value
|| stat(attr
->value
, &statbuf
)) && verbose
>= 0)
1413 _cupsLangPrintf(stdout
, _(" WARN Missing "
1414 "APPrinterIconPath file \"%s\"\n"),
1415 attr
->value
? attr
->value
: "<NULL>");
1417 #endif /* __APPLE__ */
1422 _cupsLangPrintf(stdout
, _(" %d ERRORS FOUND\n"), errors
);
1424 _cupsLangPuts(stdout
, _(" NO ERRORS FOUND\n"));
1428 * Then list the options, if "-v" was provided...
1433 _cupsLangPrintf(stdout
,
1435 " language_level = %d\n"
1436 " color_device = %s\n"
1437 " variable_sizes = %s\n"
1438 " landscape = %d\n",
1439 ppd
->language_level
,
1440 ppd
->color_device
? "TRUE" : "FALSE",
1441 ppd
->variable_sizes
? "TRUE" : "FALSE",
1444 switch (ppd
->colorspace
)
1447 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMYK\n");
1450 _cupsLangPuts(stdout
, " colorspace = PPD_CS_CMY\n");
1453 _cupsLangPuts(stdout
, " colorspace = PPD_CS_GRAY\n");
1456 _cupsLangPuts(stdout
, " colorspace = PPD_CS_RGB\n");
1459 _cupsLangPuts(stdout
, " colorspace = <unknown>\n");
1463 _cupsLangPrintf(stdout
, " num_emulations = %d\n",
1464 ppd
->num_emulations
);
1465 for (j
= 0; j
< ppd
->num_emulations
; j
++)
1466 _cupsLangPrintf(stdout
, " emulations[%d] = %s\n",
1467 j
, ppd
->emulations
[j
].name
);
1469 _cupsLangPrintf(stdout
, " lang_encoding = %s\n",
1470 ppd
->lang_encoding
);
1471 _cupsLangPrintf(stdout
, " lang_version = %s\n",
1473 _cupsLangPrintf(stdout
, " modelname = %s\n", ppd
->modelname
);
1474 _cupsLangPrintf(stdout
, " ttrasterizer = %s\n",
1475 ppd
->ttrasterizer
== NULL
? "None" : ppd
->ttrasterizer
);
1476 _cupsLangPrintf(stdout
, " manufacturer = %s\n",
1478 _cupsLangPrintf(stdout
, " product = %s\n", ppd
->product
);
1479 _cupsLangPrintf(stdout
, " nickname = %s\n", ppd
->nickname
);
1480 _cupsLangPrintf(stdout
, " shortnickname = %s\n",
1481 ppd
->shortnickname
);
1482 _cupsLangPrintf(stdout
, " patches = %d bytes\n",
1483 ppd
->patches
== NULL
? 0 : (int)strlen(ppd
->patches
));
1485 _cupsLangPrintf(stdout
, " num_groups = %d\n", ppd
->num_groups
);
1486 for (j
= 0, group
= ppd
->groups
; j
< ppd
->num_groups
; j
++, group
++)
1488 _cupsLangPrintf(stdout
, " group[%d] = %s\n",
1491 for (k
= 0, option
= group
->options
; k
< group
->num_options
; k
++, option
++)
1493 _cupsLangPrintf(stdout
,
1494 " options[%d] = %s (%s) %s %s %.0f "
1496 k
, option
->keyword
, option
->text
, uis
[option
->ui
],
1497 sections
[option
->section
], option
->order
,
1498 option
->num_choices
);
1500 if (!strcmp(option
->keyword
, "PageSize") ||
1501 !strcmp(option
->keyword
, "PageRegion"))
1503 for (m
= option
->num_choices
, choice
= option
->choices
;
1507 size
= ppdPageSize(ppd
, choice
->choice
);
1510 _cupsLangPrintf(stdout
,
1512 choice
->choice
, choice
->text
);
1514 _cupsLangPrintf(stdout
,
1515 " %s (%s) = %.2fx%.2fin "
1516 "(%.1f,%.1f,%.1f,%.1f)",
1517 choice
->choice
, choice
->text
,
1518 size
->width
/ 72.0, size
->length
/ 72.0,
1519 size
->left
/ 72.0, size
->bottom
/ 72.0,
1520 size
->right
/ 72.0, size
->top
/ 72.0);
1522 if (!strcmp(option
->defchoice
, choice
->choice
))
1523 _cupsLangPuts(stdout
, " *\n");
1525 _cupsLangPuts(stdout
, "\n");
1530 for (m
= option
->num_choices
, choice
= option
->choices
;
1534 _cupsLangPrintf(stdout
, " %s (%s)",
1535 choice
->choice
, choice
->text
);
1537 if (!strcmp(option
->defchoice
, choice
->choice
))
1538 _cupsLangPuts(stdout
, " *\n");
1540 _cupsLangPuts(stdout
, "\n");
1546 _cupsLangPrintf(stdout
, " num_profiles = %d\n",
1548 for (j
= 0; j
< ppd
->num_profiles
; j
++)
1549 _cupsLangPrintf(stdout
,
1550 " profiles[%d] = %s/%s %.3f %.3f "
1551 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1552 j
, ppd
->profiles
[j
].resolution
,
1553 ppd
->profiles
[j
].media_type
,
1554 ppd
->profiles
[j
].gamma
, ppd
->profiles
[j
].density
,
1555 ppd
->profiles
[j
].matrix
[0][0],
1556 ppd
->profiles
[j
].matrix
[0][1],
1557 ppd
->profiles
[j
].matrix
[0][2],
1558 ppd
->profiles
[j
].matrix
[1][0],
1559 ppd
->profiles
[j
].matrix
[1][1],
1560 ppd
->profiles
[j
].matrix
[1][2],
1561 ppd
->profiles
[j
].matrix
[2][0],
1562 ppd
->profiles
[j
].matrix
[2][1],
1563 ppd
->profiles
[j
].matrix
[2][2]);
1565 _cupsLangPrintf(stdout
, " num_fonts = %d\n", ppd
->num_fonts
);
1566 for (j
= 0; j
< ppd
->num_fonts
; j
++)
1567 _cupsLangPrintf(stdout
, " fonts[%d] = %s\n",
1570 _cupsLangPrintf(stdout
, " num_attrs = %d\n", ppd
->num_attrs
);
1571 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1572 _cupsLangPrintf(stdout
,
1573 " attrs[%d] = %s %s%s%s: \"%s\"\n", j
,
1574 ppd
->attrs
[j
]->name
, ppd
->attrs
[j
]->spec
,
1575 ppd
->attrs
[j
]->text
[0] ? "/" : "",
1576 ppd
->attrs
[j
]->text
,
1577 ppd
->attrs
[j
]->value
?
1578 ppd
->attrs
[j
]->value
: "(null)");
1592 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1596 check_basics(const char *filename
) /* I - PPD file to check */
1598 cups_file_t
*fp
; /* File pointer */
1599 int ch
; /* Current character */
1600 int col
, /* Current column */
1601 whitespace
; /* Only seen whitespace? */
1602 int eol
; /* Line endings */
1603 int linenum
; /* Line number */
1604 int mixed
; /* Mixed line endings? */
1607 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
1616 while ((ch
= cupsFileGetChar(fp
)) != EOF
)
1618 if (ch
== '\r' || ch
== '\n')
1622 if (eol
== EOL_NONE
)
1624 else if (eol
!= EOL_LF
)
1627 else if (ch
== '\r')
1629 if (cupsFilePeekChar(fp
) == '\n')
1631 cupsFileGetChar(fp
);
1633 if (eol
== EOL_NONE
)
1638 else if (eol
== EOL_NONE
)
1644 if (col
> 0 && whitespace
)
1645 _cupsLangPrintf(stdout
,
1646 _(" WARN Line %d only contains whitespace!\n"),
1655 if (ch
!= ' ' && ch
!= '\t')
1663 _cupsLangPuts(stdout
,
1664 _(" WARN File contains a mix of CR, LF, and "
1665 "CR LF line endings!\n"));
1667 if (eol
== EOL_CRLF
)
1668 _cupsLangPuts(stdout
,
1669 _(" WARN Non-Windows PPD files should use lines "
1670 "ending with only LF, not CR LF!\n"));
1677 * 'check_constraints()' - Check UIConstraints in the PPD file.
1680 static int /* O - Errors found */
1681 check_constraints(ppd_file_t
*ppd
, /* I - PPD file */
1682 int errors
, /* I - Errors found */
1683 int verbose
, /* I - Verbosity level */
1684 int warn
) /* I - Warnings only? */
1686 int j
; /* Looping var */
1687 ppd_const_t
*c
; /* Current constraint */
1688 ppd_option_t
*option
; /* Standard UI option */
1689 ppd_option_t
*option2
; /* Standard UI option */
1690 const char *prefix
; /* WARN/FAIL prefix */
1693 prefix
= warn
? " WARN " : "**FAIL**";
1695 for (j
= ppd
->num_consts
, c
= ppd
->consts
; j
> 0; j
--, c
++)
1697 option
= ppdFindOption(ppd
, c
->option1
);
1698 option2
= ppdFindOption(ppd
, c
->option2
);
1700 if (!option
|| !option2
)
1702 if (!warn
&& !errors
&& !verbose
)
1703 _cupsLangPuts(stdout
, _(" FAIL\n"));
1706 _cupsLangPrintf(stdout
,
1707 _(" %s Missing option %s in "
1708 "UIConstraint \"*%s %s *%s %s\"!\n"),
1710 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1713 _cupsLangPrintf(stdout
,
1714 _(" %s Missing option %s in "
1715 "UIConstraint \"*%s %s *%s %s\"!\n"),
1717 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1725 if (c
->choice1
[0] && !ppdFindChoice(option
, c
->choice1
))
1727 if (!warn
&& !errors
&& !verbose
)
1728 _cupsLangPuts(stdout
, _(" FAIL\n"));
1730 _cupsLangPrintf(stdout
,
1731 _(" %s Missing choice *%s %s in "
1732 "UIConstraint \"*%s %s *%s %s\"!\n"),
1733 prefix
, c
->option1
, c
->choice1
,
1734 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1740 if (c
->choice2
[0] && !ppdFindChoice(option2
, c
->choice2
))
1742 if (!warn
&& !errors
&& !verbose
)
1743 _cupsLangPuts(stdout
, _(" FAIL\n"));
1745 _cupsLangPrintf(stdout
,
1746 _(" %s Missing choice *%s %s in "
1747 "UIConstraint \"*%s %s *%s %s\"!\n"),
1748 prefix
, c
->option2
, c
->choice2
,
1749 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
1761 * 'check_defaults()' - Check default option keywords in the PPD file.
1764 static int /* O - Errors found */
1765 check_defaults(ppd_file_t
*ppd
, /* I - PPD file */
1766 int errors
, /* I - Errors found */
1767 int verbose
, /* I - Verbosity level */
1768 int warn
) /* I - Warnings only? */
1770 int j
, k
; /* Looping vars */
1771 ppd_attr_t
*attr
; /* PPD attribute */
1772 ppd_option_t
*option
; /* Standard UI option */
1773 const char *prefix
; /* WARN/FAIL prefix */
1776 prefix
= warn
? " WARN " : "**FAIL**";
1778 for (j
= 0; j
< ppd
->num_attrs
; j
++)
1780 attr
= ppd
->attrs
[j
];
1782 if (!strcmp(attr
->name
, "DefaultColorSpace") ||
1783 !strcmp(attr
->name
, "DefaultFont") ||
1784 !strcmp(attr
->name
, "DefaultImageableArea") ||
1785 !strcmp(attr
->name
, "DefaultOutputOrder") ||
1786 !strcmp(attr
->name
, "DefaultPaperDimension") ||
1787 !strcmp(attr
->name
, "DefaultResolution") ||
1788 !strcmp(attr
->name
, "DefaultTransfer"))
1791 if (!strncmp(attr
->name
, "Default", 7))
1793 if ((option
= ppdFindOption(ppd
, attr
->name
+ 7)) != NULL
&&
1794 strcmp(attr
->value
, "Unknown"))
1797 * Check that the default option value matches a choice...
1800 for (k
= 0; k
< option
->num_choices
; k
++)
1801 if (!strcmp(option
->choices
[k
].choice
, attr
->value
))
1804 if (k
>= option
->num_choices
)
1806 if (!warn
&& !errors
&& !verbose
)
1807 _cupsLangPuts(stdout
, _(" FAIL\n"));
1810 _cupsLangPrintf(stdout
,
1811 _(" %s %s %s does not exist!\n"),
1812 prefix
, attr
->name
, attr
->value
);
1826 * 'check_filters()' - Check filters in the PPD file.
1829 static int /* O - Errors found */
1830 check_filters(ppd_file_t
*ppd
, /* I - PPD file */
1831 const char *root
, /* I - Root directory */
1832 int errors
, /* I - Errors found */
1833 int verbose
, /* I - Verbosity level */
1834 int warn
) /* I - Warnings only? */
1836 ppd_attr_t
*attr
; /* PPD attribute */
1837 const char *ptr
; /* Pointer into string */
1838 struct stat statbuf
; /* File information */
1839 char super
[16], /* Super-type for filter */
1840 type
[256], /* Type for filter */
1841 program
[256], /* Program/filter name */
1842 pathprog
[1024]; /* Complete path to program/filter */
1843 int cost
; /* Cost of filter */
1844 const char *prefix
; /* WARN/FAIL prefix */
1847 prefix
= warn
? " WARN " : "**FAIL**";
1849 for (attr
= ppdFindAttr(ppd
, "cupsFilter", NULL
);
1851 attr
= ppdFindNextAttr(ppd
, "cupsFilter", NULL
))
1854 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1857 if (!warn
&& !errors
&& !verbose
)
1858 _cupsLangPuts(stdout
, _(" FAIL\n"));
1861 _cupsLangPrintf(stdout
,
1862 _(" %s Bad cupsFilter value \"%s\"!\n"),
1863 prefix
, attr
->value
? attr
->value
: "");
1870 if (program
[0] == '/')
1871 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1874 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1875 ptr
= CUPS_SERVERBIN
;
1877 if (*ptr
== '/' || !*root
)
1878 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1881 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1885 if (stat(pathprog
, &statbuf
))
1887 if (!warn
&& !errors
&& !verbose
)
1888 _cupsLangPuts(stdout
, _(" FAIL\n"));
1891 _cupsLangPrintf(stdout
, _(" %s Missing cupsFilter "
1892 "file \"%s\"\n"), prefix
, program
);
1900 for (attr
= ppdFindAttr(ppd
, "cupsPreFilter", NULL
);
1902 attr
= ppdFindNextAttr(ppd
, "cupsPreFilter", NULL
))
1905 sscanf(attr
->value
, "%15[^/]/%255s%d%255s", super
, type
, &cost
,
1908 if (!warn
&& !errors
&& !verbose
)
1909 _cupsLangPuts(stdout
, _(" FAIL\n"));
1912 _cupsLangPrintf(stdout
,
1913 _(" %s Bad cupsPreFilter value \"%s\"!\n"),
1914 prefix
, attr
->value
? attr
->value
: "");
1921 if (program
[0] == '/')
1922 snprintf(pathprog
, sizeof(pathprog
), "%s%s", root
, program
);
1925 if ((ptr
= getenv("CUPS_SERVERBIN")) == NULL
)
1926 ptr
= CUPS_SERVERBIN
;
1928 if (*ptr
== '/' || !*root
)
1929 snprintf(pathprog
, sizeof(pathprog
), "%s%s/filter/%s", root
, ptr
,
1932 snprintf(pathprog
, sizeof(pathprog
), "%s/%s/filter/%s", root
, ptr
,
1936 if (stat(pathprog
, &statbuf
))
1938 if (!warn
&& !errors
&& !verbose
)
1939 _cupsLangPuts(stdout
, _(" FAIL\n"));
1942 _cupsLangPrintf(stdout
, _(" %s Missing cupsPreFilter "
1943 "file \"%s\"\n"), prefix
, program
);
1956 * 'check_translations()' - Check translations in the PPD file.
1959 static int /* O - Errors found */
1960 check_translations(ppd_file_t
*ppd
, /* I - PPD file */
1961 int errors
, /* I - Errors found */
1962 int verbose
, /* I - Verbosity level */
1963 int warn
) /* I - Warnings only? */
1965 int j
; /* Looping var */
1966 ppd_attr_t
*attr
; /* PPD attribute */
1967 char *languages
, /* Copy of attribute value */
1968 *langstart
, /* Start of current language */
1969 *langptr
, /* Pointer into languages */
1970 keyword
[PPD_MAX_NAME
], /* Localization keyword (full) */
1971 llkeyword
[PPD_MAX_NAME
],/* Localization keyword (base) */
1972 ckeyword
[PPD_MAX_NAME
], /* Custom option keyword (full) */
1973 cllkeyword
[PPD_MAX_NAME
];
1974 /* Custom option keyword (base) */
1975 ppd_option_t
*option
; /* Standard UI option */
1976 ppd_coption_t
*coption
; /* Custom option */
1977 ppd_cparam_t
*cparam
; /* Custom parameter */
1978 cups_array_t
*langlist
; /* List of languages so far */
1979 char ll
[3]; /* Base language */
1980 const char *prefix
; /* WARN/FAIL prefix */
1983 prefix
= warn
? " WARN " : "**FAIL**";
1985 if ((attr
= ppdFindAttr(ppd
, "cupsLanguages", NULL
)) != NULL
&&
1989 * This file contains localizations, check them...
1992 languages
= strdup(attr
->value
);
1993 langlist
= cupsArrayNew((cups_array_func_t
)strcmp
, NULL
);
1995 for (langptr
= languages
; *langptr
;)
1998 * Skip leading whitespace...
2001 while (isspace(*langptr
& 255))
2008 * Find the end of this language name...
2011 for (langstart
= langptr
;
2012 *langptr
&& !isspace(*langptr
& 255);
2018 j
= strlen(langstart
);
2019 if (j
!= 2 && j
!= 5)
2021 if (!warn
&& !errors
&& !verbose
)
2022 _cupsLangPuts(stdout
, _(" FAIL\n"));
2025 _cupsLangPrintf(stdout
,
2026 _(" %s Bad language \"%s\"!\n"),
2035 cupsArrayAdd(langlist
, langstart
);
2037 strlcpy(ll
, langstart
, sizeof(ll
));
2040 * Loop through all options and choices...
2043 for (option
= ppdFirstOption(ppd
);
2045 option
= ppdNextOption(ppd
))
2047 snprintf(keyword
, sizeof(keyword
), "%s.Translation", langstart
);
2048 snprintf(llkeyword
, sizeof(llkeyword
), "%s.Translation", ll
);
2050 if ((attr
= ppdFindAttr(ppd
, keyword
, option
->keyword
)) == NULL
&&
2051 (attr
= ppdFindAttr(ppd
, llkeyword
, option
->keyword
)) == NULL
)
2053 if (!warn
&& !errors
&& !verbose
)
2054 _cupsLangPuts(stdout
, _(" FAIL\n"));
2057 _cupsLangPrintf(stdout
,
2058 _(" %s Missing \"%s\" translation "
2059 "string for option %s!\n"),
2060 prefix
, langstart
, option
->keyword
);
2065 else if (!valid_utf8(attr
->text
))
2067 if (!warn
&& !errors
&& !verbose
)
2068 _cupsLangPuts(stdout
, _(" FAIL\n"));
2071 _cupsLangPrintf(stdout
,
2072 _(" %s Bad UTF-8 \"%s\" translation "
2073 "string for option %s!\n"),
2074 prefix
, langstart
, option
->keyword
);
2080 snprintf(keyword
, sizeof(keyword
), "%s.%s", langstart
,
2082 snprintf(llkeyword
, sizeof(llkeyword
), "%s.%s", ll
,
2085 for (j
= 0; j
< option
->num_choices
; j
++)
2087 if (!strcasecmp(option
->choices
[j
].choice
, "Custom") &&
2088 (coption
= ppdFindCustomOption(ppd
,
2089 option
->keyword
)) != NULL
)
2091 snprintf(ckeyword
, sizeof(ckeyword
), "%s.Custom%s",
2092 langstart
, option
->keyword
);
2094 if ((attr
= ppdFindAttr(ppd
, ckeyword
, "True")) != NULL
&&
2095 !valid_utf8(attr
->text
))
2097 if (!warn
&& !errors
&& !verbose
)
2098 _cupsLangPuts(stdout
, _(" FAIL\n"));
2101 _cupsLangPrintf(stdout
,
2102 _(" %s Bad UTF-8 \"%s\" "
2103 "translation string for option %s, "
2106 ckeyword
+ 1 + strlen(langstart
),
2113 if (strcasecmp(option
->keyword
, "PageSize"))
2115 for (cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
);
2117 cparam
= (ppd_cparam_t
*)cupsArrayNext(coption
->params
))
2119 snprintf(ckeyword
, sizeof(ckeyword
), "%s.ParamCustom%s",
2120 langstart
, option
->keyword
);
2121 snprintf(cllkeyword
, sizeof(cllkeyword
), "%s.ParamCustom%s",
2122 ll
, option
->keyword
);
2124 if ((attr
= ppdFindAttr(ppd
, ckeyword
,
2125 cparam
->name
)) == NULL
&&
2126 (attr
= ppdFindAttr(ppd
, cllkeyword
,
2127 cparam
->name
)) == NULL
)
2129 if (!warn
&& !errors
&& !verbose
)
2130 _cupsLangPuts(stdout
, _(" FAIL\n"));
2133 _cupsLangPrintf(stdout
,
2134 _(" %s Missing \"%s\" "
2135 "translation string for option %s, "
2138 ckeyword
+ 1 + strlen(langstart
),
2144 else if (!valid_utf8(attr
->text
))
2146 if (!warn
&& !errors
&& !verbose
)
2147 _cupsLangPuts(stdout
, _(" FAIL\n"));
2150 _cupsLangPrintf(stdout
,
2151 _(" %s Bad UTF-8 \"%s\" "
2152 "translation string for option %s, "
2155 ckeyword
+ 1 + strlen(langstart
),
2164 else if ((attr
= ppdFindAttr(ppd
, keyword
,
2165 option
->choices
[j
].choice
)) == NULL
&&
2166 (attr
= ppdFindAttr(ppd
, llkeyword
,
2167 option
->choices
[j
].choice
)) == NULL
)
2169 if (!warn
&& !errors
&& !verbose
)
2170 _cupsLangPuts(stdout
, _(" FAIL\n"));
2173 _cupsLangPrintf(stdout
,
2174 _(" %s Missing \"%s\" "
2175 "translation string for option %s, "
2177 prefix
, langstart
, option
->keyword
,
2178 option
->choices
[j
].choice
);
2183 else if (!valid_utf8(attr
->text
))
2185 if (!warn
&& !errors
&& !verbose
)
2186 _cupsLangPuts(stdout
, _(" FAIL\n"));
2189 _cupsLangPrintf(stdout
,
2190 _(" %s Bad UTF-8 \"%s\" "
2191 "translation string for option %s, "
2193 prefix
, langstart
, option
->keyword
,
2194 option
->choices
[j
].choice
);
2204 * Verify that we have the base language for each localized one...
2207 for (langptr
= (char *)cupsArrayFirst(langlist
);
2209 langptr
= (char *)cupsArrayNext(langlist
))
2213 * Lookup the base language...
2216 cupsArraySave(langlist
);
2218 strlcpy(ll
, langptr
, sizeof(ll
));
2220 if (!cupsArrayFind(langlist
, ll
) && strcmp(ll
, "zh"))
2222 if (!warn
&& !errors
&& !verbose
)
2223 _cupsLangPuts(stdout
, _(" FAIL\n"));
2226 _cupsLangPrintf(stdout
,
2227 _(" %s No base translation \"%s\" "
2228 "is included in file!\n"), prefix
, ll
);
2234 cupsArrayRestore(langlist
);
2238 * Free memory used for the languages...
2241 cupsArrayDelete(langlist
);
2250 * 'show_conflicts()' - Show option conflicts in a PPD file.
2254 show_conflicts(ppd_file_t
*ppd
) /* I - PPD to check */
2256 int i
, j
; /* Looping variables */
2257 ppd_const_t
*c
; /* Current constraint */
2258 ppd_option_t
*o1
, *o2
; /* Options */
2259 ppd_choice_t
*c1
, *c2
; /* Choices */
2263 * Loop through all of the UI constraints and report any options
2267 for (i
= ppd
->num_consts
, c
= ppd
->consts
; i
> 0; i
--, c
++)
2270 * Grab pointers to the first option...
2273 o1
= ppdFindOption(ppd
, c
->option1
);
2277 else if (c
->choice1
[0] != '\0')
2280 * This constraint maps to a specific choice.
2283 c1
= ppdFindChoice(o1
, c
->choice1
);
2288 * This constraint applies to any choice for this option.
2291 for (j
= o1
->num_choices
, c1
= o1
->choices
; j
> 0; j
--, c1
++)
2296 !strcasecmp(c1
->choice
, "None") ||
2297 !strcasecmp(c1
->choice
, "Off") ||
2298 !strcasecmp(c1
->choice
, "False"))
2303 * Grab pointers to the second option...
2306 o2
= ppdFindOption(ppd
, c
->option2
);
2310 else if (c
->choice2
[0] != '\0')
2313 * This constraint maps to a specific choice.
2316 c2
= ppdFindChoice(o2
, c
->choice2
);
2321 * This constraint applies to any choice for this option.
2324 for (j
= o2
->num_choices
, c2
= o2
->choices
; j
> 0; j
--, c2
++)
2329 !strcasecmp(c2
->choice
, "None") ||
2330 !strcasecmp(c2
->choice
, "Off") ||
2331 !strcasecmp(c2
->choice
, "False"))
2336 * If both options are marked then there is a conflict...
2339 if (c1
!= NULL
&& c1
->marked
&& c2
!= NULL
&& c2
->marked
)
2340 _cupsLangPrintf(stdout
,
2341 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
2342 " (constraint=\"%s %s %s %s\")\n"),
2343 o1
->keyword
, c1
->choice
, o2
->keyword
, c2
->choice
,
2344 c
->option1
, c
->choice1
, c
->option2
, c
->choice2
);
2350 * 'usage()' - Show program usage...
2356 _cupsLangPuts(stdout
,
2357 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
2358 "[... filenameN.ppd[.gz]]\n"
2359 " program | cupstestppd [options] -\n"
2363 " -R root-directory Set alternate root\n"
2364 " -W {all,none,constraints,defaults,filters,translations}\n"
2365 " Issue warnings instead of errors\n"
2366 " -q Run silently\n"
2367 " -r Use 'relaxed' open mode\n"
2368 " -v Be slightly verbose\n"
2369 " -vv Be very verbose\n"));
2376 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
2379 static int /* O - 1 if valid, 0 if not */
2380 valid_utf8(const char *s
) /* I - String to check */
2387 * Check for valid UTF-8 sequence...
2390 if ((*s
& 0xc0) == 0x80)
2391 return (0); /* Illegal suffix byte */
2392 else if ((*s
& 0xe0) == 0xc0)
2395 * 2-byte sequence...
2400 if ((*s
& 0xc0) != 0x80)
2401 return (0); /* Missing suffix byte */
2403 else if ((*s
& 0xf0) == 0xe0)
2406 * 3-byte sequence...
2411 if ((*s
& 0xc0) != 0x80)
2412 return (0); /* Missing suffix byte */
2416 if ((*s
& 0xc0) != 0x80)
2417 return (0); /* Missing suffix byte */
2419 else if ((*s
& 0xf8) == 0xf0)
2422 * 4-byte sequence...
2427 if ((*s
& 0xc0) != 0x80)
2428 return (0); /* Missing suffix byte */
2432 if ((*s
& 0xc0) != 0x80)
2433 return (0); /* Missing suffix byte */
2437 if ((*s
& 0xc0) != 0x80)
2438 return (0); /* Missing suffix byte */
2441 return (0); /* Bad sequence */
2452 * End of "$Id: cupstestppd.c 6533 2007-05-15 15:54:23Z mike $".