]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/cupstestppd.c
Load cups into easysw/current.
[thirdparty/cups.git] / systemv / cupstestppd.c
1 /*
2 * "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $"
3 *
4 * PPD test program for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
7 *
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
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * PostScript is a trademark of Adobe Systems, Inc.
25 *
26 * This file is subject to the Apple OS-Developed Software exception.
27 *
28 * Contents:
29 *
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.
34 */
35
36 /*
37 * Include necessary headers...
38 */
39
40 #include <cups/string.h>
41 #include <cups/cups.h>
42 #include <cups/i18n.h>
43 #include <errno.h>
44 #include <stdlib.h>
45 #include <sys/stat.h>
46
47
48 /*
49 * Error warning overrides...
50 */
51
52 enum
53 {
54 WARN_NONE = 0,
55 WARN_CONSTRAINTS = 1,
56 WARN_DEFAULTS = 2,
57 WARN_FILTERS = 4,
58 WARN_TRANSLATIONS = 8,
59 WARN_ALL = 15
60 };
61
62
63 /*
64 * Error codes...
65 */
66
67 enum
68 {
69 ERROR_NONE = 0,
70 ERROR_USAGE,
71 ERROR_FILE_OPEN,
72 ERROR_PPD_FORMAT,
73 ERROR_CONFORMANCE
74 };
75
76
77 /*
78 * Line endings...
79 */
80
81 enum
82 {
83 EOL_NONE = 0,
84 EOL_CR,
85 EOL_LF,
86 EOL_CRLF
87 };
88
89
90 /*
91 * Local functions...
92 */
93
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);
101 void usage(void);
102 int valid_utf8(const char *s);
103
104
105 /*
106 * 'main()' - Main entry for test program.
107 */
108
109 int /* O - Exit status */
110 main(int argc, /* I - Number of command-line args */
111 char *argv[]) /* I - Command-line arguments */
112 {
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" };
141
142
143 _cupsSetLocale(argv);
144
145 /*
146 * Display PPD files for each file listed on the command-line...
147 */
148
149 ppdSetConformance(PPD_CONFORM_STRICT);
150
151 verbose = 0;
152 ppd = NULL;
153 files = 0;
154 status = ERROR_NONE;
155 root = "";
156 warn = WARN_NONE;
157
158 for (i = 1; i < argc; i ++)
159 if (argv[i][0] == '-' && argv[i][1])
160 {
161 for (opt = argv[i] + 1; *opt; opt ++)
162 switch (*opt)
163 {
164 case 'R' : /* Alternate root directory */
165 i ++;
166
167 if (i >= argc)
168 usage();
169
170 root = argv[i];
171 break;
172
173 case 'W' : /* Turn errors into warnings */
174 i ++;
175
176 if (i >= argc)
177 usage();
178
179 if (!strcmp(argv[i], "none"))
180 warn = WARN_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"))
190 warn = WARN_ALL;
191 else
192 usage();
193 break;
194
195 case 'q' : /* Quiet mode */
196 if (verbose > 0)
197 {
198 _cupsLangPuts(stderr,
199 _("cupstestppd: The -q option is incompatible "
200 "with the -v option.\n"));
201 return (1);
202 }
203
204 verbose --;
205 break;
206
207 case 'r' : /* Relaxed mode */
208 ppdSetConformance(PPD_CONFORM_RELAXED);
209 break;
210
211 case 'v' : /* Verbose mode */
212 if (verbose < 0)
213 {
214 _cupsLangPuts(stderr,
215 _("cupstestppd: The -v option is incompatible "
216 "with the -q option.\n"));
217 return (1);
218 }
219
220 verbose ++;
221 break;
222
223 default :
224 usage();
225 break;
226 }
227 }
228 else
229 {
230 /*
231 * Open the PPD file...
232 */
233
234 if (files && verbose >= 0)
235 _cupsLangPuts(stdout, "\n");
236
237 files ++;
238
239 if (argv[i][0] == '-')
240 {
241 /*
242 * Read from stdin...
243 */
244
245 if (verbose >= 0)
246 printf("(stdin):");
247
248 ppd = ppdOpen(stdin);
249 }
250 else
251 {
252 /*
253 * Read from a file...
254 */
255
256 if (verbose >= 0)
257 printf("%s:", argv[i]);
258
259 ppd = ppdOpenFile(argv[i]);
260 }
261
262 if (ppd == NULL)
263 {
264 error = ppdLastError(&line);
265
266 if (error <= PPD_ALLOC_ERROR)
267 {
268 status = ERROR_FILE_OPEN;
269
270 if (verbose >= 0)
271 _cupsLangPrintf(stdout,
272 _(" FAIL\n"
273 " **FAIL** Unable to open PPD file - %s\n"),
274 strerror(errno));
275 }
276 else
277 {
278 status = ERROR_PPD_FORMAT;
279
280 if (verbose >= 0)
281 {
282 _cupsLangPrintf(stdout,
283 _(" FAIL\n"
284 " **FAIL** Unable to open PPD file - "
285 "%s on line %d.\n"),
286 ppdErrorString(error), line);
287
288 switch (error)
289 {
290 case PPD_MISSING_PPDADOBE4 :
291 _cupsLangPuts(stdout,
292 _(" REF: Page 42, section 5.2.\n"));
293 break;
294 case PPD_MISSING_VALUE :
295 _cupsLangPuts(stdout,
296 _(" REF: Page 20, section 3.4.\n"));
297 break;
298 case PPD_BAD_OPEN_GROUP :
299 case PPD_NESTED_OPEN_GROUP :
300 _cupsLangPuts(stdout,
301 _(" REF: Pages 45-46, section 5.2.\n"));
302 break;
303 case PPD_BAD_OPEN_UI :
304 case PPD_NESTED_OPEN_UI :
305 _cupsLangPuts(stdout,
306 _(" REF: Pages 42-45, section 5.2.\n"));
307 break;
308 case PPD_BAD_ORDER_DEPENDENCY :
309 _cupsLangPuts(stdout,
310 _(" REF: Pages 48-49, section 5.2.\n"));
311 break;
312 case PPD_BAD_UI_CONSTRAINTS :
313 _cupsLangPuts(stdout,
314 _(" REF: Pages 52-54, section 5.2.\n"));
315 break;
316 case PPD_MISSING_ASTERISK :
317 _cupsLangPuts(stdout,
318 _(" REF: Page 15, section 3.2.\n"));
319 break;
320 case PPD_LINE_TOO_LONG :
321 _cupsLangPuts(stdout,
322 _(" REF: Page 15, section 3.1.\n"));
323 break;
324 case PPD_ILLEGAL_CHARACTER :
325 _cupsLangPuts(stdout,
326 _(" REF: Page 15, section 3.1.\n"));
327 break;
328 case PPD_ILLEGAL_MAIN_KEYWORD :
329 _cupsLangPuts(stdout,
330 _(" REF: Pages 16-17, section 3.2.\n"));
331 break;
332 case PPD_ILLEGAL_OPTION_KEYWORD :
333 _cupsLangPuts(stdout,
334 _(" REF: Page 19, section 3.3.\n"));
335 break;
336 case PPD_ILLEGAL_TRANSLATION :
337 _cupsLangPuts(stdout,
338 _(" REF: Page 27, section 3.5.\n"));
339 break;
340 default :
341 break;
342 }
343
344 check_basics(argv[i]);
345 }
346 }
347
348 continue;
349 }
350
351 /*
352 * Show the header and then perform basic conformance tests (limited
353 * only by what the CUPS PPD functions actually load...)
354 */
355
356 errors = 0;
357 ppdversion = 43;
358
359 if (verbose > 0)
360 _cupsLangPuts(stdout,
361 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
362
363 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
364 attr->value)
365 ppdversion = (int)(10 * atof(attr->value) + 0.5);
366
367 /*
368 * Look for default keywords with no matching option...
369 */
370
371 if (!(warn & WARN_DEFAULTS))
372 errors = check_defaults(ppd, errors, verbose, 0);
373
374 if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
375 {
376 if (verbose >= 0)
377 {
378 if (!errors && !verbose)
379 _cupsLangPuts(stdout, _(" FAIL\n"));
380
381 _cupsLangPuts(stdout,
382 _(" **FAIL** REQUIRED DefaultImageableArea\n"
383 " REF: Page 102, section 5.15.\n"));
384 }
385
386 errors ++;
387 }
388 else if (ppdPageSize(ppd, attr->value) == NULL &&
389 strcmp(attr->value, "Unknown"))
390 {
391 if (verbose >= 0)
392 {
393 if (!errors && !verbose)
394 _cupsLangPuts(stdout, _(" FAIL\n"));
395
396 _cupsLangPrintf(stdout,
397 _(" **FAIL** BAD DefaultImageableArea %s!\n"
398 " REF: Page 102, section 5.15.\n"),
399 attr->value);
400 }
401
402 errors ++;
403 }
404 else
405 {
406 if (verbose > 0)
407 _cupsLangPuts(stdout, _(" PASS DefaultImageableArea\n"));
408 }
409
410 if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL)
411 {
412 if (verbose >= 0)
413 {
414 if (!errors && !verbose)
415 _cupsLangPuts(stdout, _(" FAIL\n"));
416
417 _cupsLangPuts(stdout,
418 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
419 " REF: Page 103, section 5.15.\n"));
420 }
421
422 errors ++;
423 }
424 else if (ppdPageSize(ppd, attr->value) == NULL &&
425 strcmp(attr->value, "Unknown"))
426 {
427 if (verbose >= 0)
428 {
429 if (!errors && !verbose)
430 _cupsLangPuts(stdout, _(" FAIL\n"));
431
432 _cupsLangPrintf(stdout,
433 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
434 " REF: Page 103, section 5.15.\n"),
435 attr->value);
436 }
437
438 errors ++;
439 }
440 else if (verbose > 0)
441 _cupsLangPuts(stdout, _(" PASS DefaultPaperDimension\n"));
442
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 ++)
445 {
446 /*
447 * Verify that we have a default choice...
448 */
449
450 if (option->defchoice[0])
451 {
452 if (ppdFindChoice(option, option->defchoice) == NULL &&
453 strcmp(option->defchoice, "Unknown"))
454 {
455 if (verbose >= 0)
456 {
457 if (!errors && !verbose)
458 _cupsLangPuts(stdout, _(" FAIL\n"));
459
460 _cupsLangPrintf(stdout,
461 _(" **FAIL** BAD Default%s %s\n"
462 " REF: Page 40, section 4.5.\n"),
463 option->keyword, option->defchoice);
464 }
465
466 errors ++;
467 }
468 else if (verbose > 0)
469 _cupsLangPrintf(stdout,
470 _(" PASS Default%s\n"),
471 option->keyword);
472 }
473 else
474 {
475 if (verbose >= 0)
476 {
477 if (!errors && !verbose)
478 _cupsLangPuts(stdout, _(" FAIL\n"));
479
480 _cupsLangPrintf(stdout,
481 _(" **FAIL** REQUIRED Default%s\n"
482 " REF: Page 40, section 4.5.\n"),
483 option->keyword);
484 }
485
486 errors ++;
487 }
488 }
489
490 if (ppdFindAttr(ppd, "FileVersion", NULL) != NULL)
491 {
492 if (verbose > 0)
493 _cupsLangPuts(stdout, _(" PASS FileVersion\n"));
494 }
495 else
496 {
497 if (verbose >= 0)
498 {
499 if (!errors && !verbose)
500 _cupsLangPuts(stdout, _(" FAIL\n"));
501
502 _cupsLangPuts(stdout,
503 _(" **FAIL** REQUIRED FileVersion\n"
504 " REF: Page 56, section 5.3.\n"));
505 }
506
507 errors ++;
508 }
509
510 if (ppdFindAttr(ppd, "FormatVersion", NULL) != NULL)
511 {
512 if (verbose > 0)
513 _cupsLangPuts(stdout, _(" PASS FormatVersion\n"));
514 }
515 else
516 {
517 if (verbose >= 0)
518 {
519 if (!errors && !verbose)
520 _cupsLangPuts(stdout, _(" FAIL\n"));
521
522 _cupsLangPuts(stdout,
523 _(" **FAIL** REQUIRED FormatVersion\n"
524 " REF: Page 56, section 5.3.\n"));
525 }
526
527 errors ++;
528 }
529
530 if (ppd->lang_encoding != NULL)
531 {
532 if (verbose > 0)
533 _cupsLangPuts(stdout, _(" PASS LanguageEncoding\n"));
534 }
535 else if (ppdversion > 40)
536 {
537 if (verbose >= 0)
538 {
539 if (!errors && !verbose)
540 _cupsLangPuts(stdout, _(" FAIL\n"));
541
542 _cupsLangPuts(stdout,
543 _(" **FAIL** REQUIRED LanguageEncoding\n"
544 " REF: Pages 56-57, section 5.3.\n"));
545 }
546
547 errors ++;
548 }
549
550 if (ppd->lang_version != NULL)
551 {
552 if (verbose > 0)
553 _cupsLangPuts(stdout, _(" PASS LanguageVersion\n"));
554 }
555 else
556 {
557 if (verbose >= 0)
558 {
559 if (!errors && !verbose)
560 _cupsLangPuts(stdout, _(" FAIL\n"));
561
562 _cupsLangPuts(stdout,
563 _(" **FAIL** REQUIRED LanguageVersion\n"
564 " REF: Pages 57-58, section 5.3.\n"));
565 }
566
567 errors ++;
568 }
569
570 if (ppd->manufacturer != NULL)
571 {
572 if (!strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) ||
573 !strncasecmp(ppd->manufacturer, "Hewlett Packard", 15))
574 {
575 if (verbose >= 0)
576 {
577 if (!errors && !verbose)
578 _cupsLangPuts(stdout, _(" FAIL\n"));
579
580 _cupsLangPuts(stdout,
581 _(" **FAIL** BAD Manufacturer (should be "
582 "\"HP\")\n"
583 " REF: Page 211, table D.1.\n"));
584 }
585
586 errors ++;
587 }
588 else if (!strncasecmp(ppd->manufacturer, "OkiData", 7) ||
589 !strncasecmp(ppd->manufacturer, "Oki Data", 8))
590 {
591 if (verbose >= 0)
592 {
593 if (!errors && !verbose)
594 _cupsLangPuts(stdout, _(" FAIL\n"));
595
596 _cupsLangPuts(stdout,
597 _(" **FAIL** BAD Manufacturer (should be "
598 "\"Oki\")\n"
599 " REF: Page 211, table D.1.\n"));
600 }
601
602 errors ++;
603 }
604 else if (verbose > 0)
605 _cupsLangPuts(stdout, _(" PASS Manufacturer\n"));
606 }
607 else if (ppdversion >= 43)
608 {
609 if (verbose >= 0)
610 {
611 if (!errors && !verbose)
612 _cupsLangPuts(stdout, _(" FAIL\n"));
613
614 _cupsLangPuts(stdout,
615 _(" **FAIL** REQUIRED Manufacturer\n"
616 " REF: Pages 58-59, section 5.3.\n"));
617 }
618
619 errors ++;
620 }
621
622 if (ppd->modelname != NULL)
623 {
624 for (ptr = ppd->modelname; *ptr; ptr ++)
625 if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr))
626 break;
627
628 if (*ptr)
629 {
630 if (verbose >= 0)
631 {
632 if (!errors && !verbose)
633 _cupsLangPuts(stdout, _(" FAIL\n"));
634
635 _cupsLangPrintf(stdout,
636 _(" **FAIL** BAD ModelName - \"%c\" not "
637 "allowed in string.\n"
638 " REF: Pages 59-60, section 5.3.\n"),
639 *ptr);
640 }
641
642 errors ++;
643 }
644 else if (verbose > 0)
645 _cupsLangPuts(stdout, _(" PASS ModelName\n"));
646 }
647 else
648 {
649 if (verbose >= 0)
650 {
651 if (!errors && !verbose)
652 _cupsLangPuts(stdout, _(" FAIL\n"));
653
654 _cupsLangPuts(stdout,
655 _(" **FAIL** REQUIRED ModelName\n"
656 " REF: Pages 59-60, section 5.3.\n"));
657 }
658
659 errors ++;
660 }
661
662 if (ppd->nickname != NULL)
663 {
664 if (verbose > 0)
665 _cupsLangPuts(stdout, _(" PASS NickName\n"));
666 }
667 else
668 {
669 if (verbose >= 0)
670 {
671 if (!errors && !verbose)
672 _cupsLangPuts(stdout, _(" FAIL\n"));
673
674 _cupsLangPuts(stdout,
675 _(" **FAIL** REQUIRED NickName\n"
676 " REF: Page 60, section 5.3.\n"));
677 }
678
679 errors ++;
680 }
681
682 if (ppdFindOption(ppd, "PageSize") != NULL)
683 {
684 if (verbose > 0)
685 _cupsLangPuts(stdout, _(" PASS PageSize\n"));
686 }
687 else
688 {
689 if (verbose >= 0)
690 {
691 if (!errors && !verbose)
692 _cupsLangPuts(stdout, _(" FAIL\n"));
693
694 _cupsLangPuts(stdout,
695 _(" **FAIL** REQUIRED PageSize\n"
696 " REF: Pages 99-100, section 5.14.\n"));
697 }
698
699 errors ++;
700 }
701
702 if (ppdFindOption(ppd, "PageRegion") != NULL)
703 {
704 if (verbose > 0)
705 _cupsLangPuts(stdout, _(" PASS PageRegion\n"));
706 }
707 else
708 {
709 if (verbose >= 0)
710 {
711 if (!errors && !verbose)
712 _cupsLangPuts(stdout, _(" FAIL\n"));
713
714 _cupsLangPuts(stdout,
715 _(" **FAIL** REQUIRED PageRegion\n"
716 " REF: Page 100, section 5.14.\n"));
717 }
718
719 errors ++;
720 }
721
722 if (ppd->pcfilename != NULL)
723 {
724 if (verbose > 0)
725 _cupsLangPuts(stdout, _(" PASS PCFileName\n"));
726 }
727 else
728 {
729 if (verbose >= 0)
730 {
731 if (!errors && !verbose)
732 _cupsLangPuts(stdout, _(" FAIL\n"));
733
734 _cupsLangPuts(stdout,
735 _(" **FAIL** REQUIRED PCFileName\n"
736 " REF: Pages 61-62, section 5.3.\n"));
737 }
738
739 errors ++;
740 }
741
742 if (ppd->product != NULL)
743 {
744 if (ppd->product[0] != '(' ||
745 ppd->product[strlen(ppd->product) - 1] != ')')
746 {
747 if (verbose >= 0)
748 {
749 if (!errors && !verbose)
750 _cupsLangPuts(stdout, _(" FAIL\n"));
751
752 _cupsLangPuts(stdout,
753 _(" **FAIL** BAD Product - not \"(string)\".\n"
754 " REF: Page 62, section 5.3.\n"));
755 }
756
757 errors ++;
758 }
759 else if (verbose > 0)
760 _cupsLangPuts(stdout, _(" PASS Product\n"));
761 }
762 else
763 {
764 if (verbose >= 0)
765 {
766 if (!errors && !verbose)
767 _cupsLangPuts(stdout, _(" FAIL\n"));
768
769 _cupsLangPuts(stdout,
770 _(" **FAIL** REQUIRED Product\n"
771 " REF: Page 62, section 5.3.\n"));
772 }
773
774 errors ++;
775 }
776
777 if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL &&
778 attr->value != NULL)
779 {
780 char junkstr[255]; /* Temp string */
781 int junkint; /* Temp integer */
782
783
784 if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2)
785 {
786 if (verbose >= 0)
787 {
788 if (!errors && !verbose)
789 _cupsLangPuts(stdout, _(" FAIL\n"));
790
791 _cupsLangPuts(stdout,
792 _(" **FAIL** BAD PSVersion - not \"(string) "
793 "int\".\n"
794 " REF: Pages 62-64, section 5.3.\n"));
795 }
796
797 errors ++;
798 }
799 else if (verbose > 0)
800 _cupsLangPuts(stdout, _(" PASS PSVersion\n"));
801 }
802 else
803 {
804 if (verbose >= 0)
805 {
806 if (!errors && !verbose)
807 _cupsLangPuts(stdout, _(" FAIL\n"));
808
809 _cupsLangPuts(stdout,
810 _(" **FAIL** REQUIRED PSVersion\n"
811 " REF: Pages 62-64, section 5.3.\n"));
812 }
813
814 errors ++;
815 }
816
817 if (ppd->shortnickname != NULL)
818 {
819 if (strlen(ppd->shortnickname) > 31)
820 {
821 if (verbose >= 0)
822 {
823 if (!errors && !verbose)
824 _cupsLangPuts(stdout, _(" FAIL\n"));
825
826 _cupsLangPuts(stdout,
827 _(" **FAIL** BAD ShortNickName - longer "
828 "than 31 chars.\n"
829 " REF: Pages 64-65, section 5.3.\n"));
830 }
831
832 errors ++;
833 }
834 else if (verbose > 0)
835 _cupsLangPuts(stdout, _(" PASS ShortNickName\n"));
836 }
837 else if (ppdversion >= 43)
838 {
839 if (verbose >= 0)
840 {
841 if (!errors && !verbose)
842 _cupsLangPuts(stdout, _(" FAIL\n"));
843
844 _cupsLangPuts(stdout,
845 _(" **FAIL** REQUIRED ShortNickName\n"
846 " REF: Page 64-65, section 5.3.\n"));
847 }
848
849 errors ++;
850 }
851
852 if (ppd->patches != NULL && strchr(ppd->patches, '\"') &&
853 strstr(ppd->patches, "*End"))
854 {
855 if (verbose >= 0)
856 {
857 if (!errors && !verbose)
858 _cupsLangPuts(stdout, _(" FAIL\n"));
859
860 _cupsLangPuts(stdout,
861 _(" **FAIL** BAD JobPatchFile attribute in file\n"
862 " REF: Page 24, section 3.4.\n"));
863 }
864
865 errors ++;
866 }
867
868 /*
869 * Check for page sizes without the corresponding ImageableArea or
870 * PaperDimension values...
871 */
872
873 if (ppd->num_sizes == 0)
874 {
875 if (verbose >= 0)
876 {
877 if (!errors && !verbose)
878 _cupsLangPuts(stdout, _(" FAIL\n"));
879
880 _cupsLangPuts(stdout,
881 _(" **FAIL** REQUIRED PageSize\n"
882 " REF: Page 41, section 5.\n"
883 " REF: Page 99, section 5.14.\n"));
884 }
885
886 errors ++;
887 }
888 else
889 {
890 for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++)
891 {
892 /*
893 * Don't check custom size...
894 */
895
896 if (!strcmp(size->name, "Custom"))
897 continue;
898
899 /*
900 * Check for ImageableArea...
901 */
902
903 if (size->left == 0.0 && size->bottom == 0.0 &&
904 size->right == 0.0 && size->top == 0.0)
905 {
906 if (verbose >= 0)
907 {
908 if (!errors && !verbose)
909 _cupsLangPuts(stdout, _(" FAIL\n"));
910
911 _cupsLangPrintf(stdout,
912 _(" **FAIL** REQUIRED ImageableArea for "
913 "PageSize %s\n"
914 " REF: Page 41, section 5.\n"
915 " REF: Page 102, section 5.15.\n"),
916 size->name);
917 }
918
919 errors ++;
920 }
921
922 /*
923 * Check for PaperDimension...
924 */
925
926 if (size->width == 0.0 && size->length == 0.0)
927 {
928 if (verbose >= 0)
929 {
930 if (!errors && !verbose)
931 _cupsLangPuts(stdout, _(" FAIL\n"));
932
933 _cupsLangPrintf(stdout,
934 _(" **FAIL** REQUIRED PaperDimension "
935 "for PageSize %s\n"
936 " REF: Page 41, section 5.\n"
937 " REF: Page 103, section 5.15.\n"),
938 size->name);
939 }
940
941 errors ++;
942 }
943 }
944 }
945
946 /*
947 * Check for valid Resolution, JCLResolution, or SetResolution values...
948 */
949
950 if ((option = ppdFindOption(ppd, "Resolution")) == NULL)
951 if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL)
952 option = ppdFindOption(ppd, "SetResolution");
953
954 if (option != NULL)
955 {
956 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
957 {
958 /*
959 * Verify that all resolution options are of the form NNNdpi
960 * or NNNxNNNdpi...
961 */
962
963 xdpi = strtol(choice->choice, (char **)&ptr, 10);
964 if (ptr > choice->choice && xdpi > 0)
965 {
966 if (*ptr == 'x')
967 ydpi = strtol(ptr + 1, (char **)&ptr, 10);
968 else
969 ydpi = xdpi;
970 }
971 else
972 ydpi = xdpi;
973
974 if (xdpi <= 0 || ydpi <= 0 || strcmp(ptr, "dpi"))
975 {
976 if (verbose >= 0)
977 {
978 if (!errors && !verbose)
979 _cupsLangPuts(stdout, _(" FAIL\n"));
980
981 _cupsLangPrintf(stdout,
982 _(" **FAIL** Bad %s choice %s!\n"
983 " REF: Page 84, section 5.9\n"),
984 option->keyword, choice->choice);
985 }
986
987 errors ++;
988 }
989 }
990 }
991
992 /*
993 * Check for a duplex option, and for standard values...
994 */
995
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");
1000
1001 if (option != NULL)
1002 {
1003 if (ppdFindChoice(option, "None") == NULL)
1004 {
1005 if (verbose >= 0)
1006 {
1007 if (!errors && !verbose)
1008 _cupsLangPuts(stdout, _(" FAIL\n"));
1009
1010 _cupsLangPrintf(stdout,
1011 _(" **FAIL** REQUIRED %s does not define "
1012 "choice None!\n"
1013 " REF: Page 122, section 5.17\n"),
1014 option->keyword);
1015 }
1016
1017 errors ++;
1018 }
1019
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"))
1025 {
1026 if (verbose >= 0)
1027 {
1028 if (!errors && !verbose)
1029 _cupsLangPuts(stdout, _(" FAIL\n"));
1030
1031 _cupsLangPrintf(stdout,
1032 _(" **FAIL** Bad %s choice %s!\n"
1033 " REF: Page 122, section 5.17\n"),
1034 option->keyword, choice->choice);
1035 }
1036
1037 errors ++;
1038 }
1039 }
1040
1041 if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
1042 strcmp(attr->name, "1284DeviceID"))
1043 {
1044 if (verbose >= 0)
1045 {
1046 if (!errors && !verbose)
1047 _cupsLangPuts(stdout, _(" FAIL\n"));
1048
1049 _cupsLangPrintf(stdout,
1050 _(" **FAIL** %s must be 1284DeviceID!\n"
1051 " REF: Page 72, section 5.5\n"),
1052 attr->name);
1053 }
1054
1055 errors ++;
1056 }
1057
1058 if (!(warn & WARN_CONSTRAINTS))
1059 errors = check_constraints(ppd, errors, verbose, 0);
1060
1061 if (!(warn & WARN_FILTERS))
1062 errors = check_filters(ppd, root, errors, verbose, 0);
1063
1064 if (!(warn & WARN_TRANSLATIONS))
1065 errors = check_translations(ppd, errors, verbose, 0);
1066
1067 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
1068 attr->value)
1069 {
1070 /*
1071 * This file contains localizations, check for conformance of the
1072 * base translation...
1073 */
1074
1075 if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL)
1076 {
1077 if (!attr->value || strcmp(attr->value, "ISOLatin1"))
1078 {
1079 if (!errors && !verbose)
1080 _cupsLangPuts(stdout, _(" FAIL\n"));
1081
1082 if (verbose >= 0)
1083 _cupsLangPrintf(stderr,
1084 _(" **FAIL** Bad LanguageEncoding %s - "
1085 "must be ISOLatin1!\n"),
1086 attr->value ? attr->value : "(null)");
1087
1088 errors ++;
1089 }
1090
1091 if (!ppd->lang_version || strcmp(ppd->lang_version, "English"))
1092 {
1093 if (!errors && !verbose)
1094 _cupsLangPuts(stdout, _(" FAIL\n"));
1095
1096 if (verbose >= 0)
1097 _cupsLangPrintf(stderr,
1098 _(" **FAIL** Bad LanguageVersion %s - "
1099 "must be English!\n"),
1100 ppd->lang_version ? ppd->lang_version : "(null)");
1101
1102 errors ++;
1103 }
1104
1105 /*
1106 * Loop through all options and choices...
1107 */
1108
1109 for (option = ppdFirstOption(ppd);
1110 option;
1111 option = ppdNextOption(ppd))
1112 {
1113 /*
1114 * Check for special characters outside A0 to BF, F7, or F8
1115 * that are used for languages other than English.
1116 */
1117
1118 for (ptr = option->text; *ptr; ptr ++)
1119 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
1120 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
1121 break;
1122
1123 if (*ptr)
1124 {
1125 if (!errors && !verbose)
1126 _cupsLangPuts(stdout, _(" FAIL\n"));
1127
1128 if (verbose >= 0)
1129 _cupsLangPrintf(stdout,
1130 _(" **FAIL** Default translation "
1131 "string for option %s contains 8-bit "
1132 "characters!\n"),
1133 option->keyword);
1134
1135 errors ++;
1136 }
1137
1138 for (j = 0; j < option->num_choices; j ++)
1139 {
1140 /*
1141 * Check for special characters outside A0 to BF, F7, or F8
1142 * that are used for languages other than English.
1143 */
1144
1145 for (ptr = option->choices[j].text; *ptr; ptr ++)
1146 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
1147 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
1148 break;
1149
1150 if (*ptr)
1151 {
1152 if (!errors && !verbose)
1153 _cupsLangPuts(stdout, _(" FAIL\n"));
1154
1155 if (verbose >= 0)
1156 _cupsLangPrintf(stdout,
1157 _(" **FAIL** Default translation "
1158 "string for option %s choice %s contains "
1159 "8-bit characters!\n"),
1160 option->keyword,
1161 option->choices[j].choice);
1162
1163 errors ++;
1164 }
1165 }
1166 }
1167 }
1168 }
1169
1170 /*
1171 * Final pass/fail notification...
1172 */
1173
1174 if (errors)
1175 status = ERROR_CONFORMANCE;
1176 else if (!verbose)
1177 _cupsLangPuts(stdout, _(" PASS\n"));
1178
1179 if (verbose >= 0)
1180 {
1181 check_basics(argv[i]);
1182
1183 if (warn & WARN_CONSTRAINTS)
1184 errors = check_constraints(ppd, errors, verbose, 1);
1185
1186 if (warn & WARN_DEFAULTS)
1187 errors = check_defaults(ppd, errors, verbose, 1);
1188
1189 if (warn & WARN_FILTERS)
1190 errors = check_filters(ppd, root, errors, verbose, 1);
1191
1192 if (warn & WARN_TRANSLATIONS)
1193 errors = check_translations(ppd, errors, verbose, 1);
1194
1195 /*
1196 * Look for default keywords with no corresponding option...
1197 */
1198
1199 for (j = 0; j < ppd->num_attrs; j ++)
1200 {
1201 attr = ppd->attrs[j];
1202
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"))
1211 continue;
1212
1213 if (!strncmp(attr->name, "Default", 7) &&
1214 !ppdFindOption(ppd, attr->name + 7))
1215 _cupsLangPrintf(stdout,
1216 _(" WARN %s has no corresponding "
1217 "options!\n"),
1218 attr->name);
1219 }
1220
1221 /*
1222 * Check for old Duplex option names...
1223 */
1224
1225 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
1226 option = ppdFindOption(ppd, "KD03Duplex");
1227
1228 if (option)
1229 {
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"),
1234 option->keyword);
1235 }
1236
1237 ppdMarkDefaults(ppd);
1238 if (ppdConflicts(ppd))
1239 {
1240 _cupsLangPuts(stdout,
1241 _(" WARN Default choices conflicting!\n"));
1242
1243 show_conflicts(ppd);
1244 }
1245
1246 if (ppdversion < 43)
1247 {
1248 _cupsLangPrintf(stdout,
1249 _(" WARN Obsolete PPD version %.1f!\n"
1250 " REF: Page 42, section 5.2.\n"),
1251 0.1f * ppdversion);
1252 }
1253
1254 if (!ppd->lang_encoding && ppdversion < 41)
1255 {
1256 _cupsLangPuts(stdout,
1257 _(" WARN LanguageEncoding required by PPD "
1258 "4.3 spec.\n"
1259 " REF: Pages 56-57, section 5.3.\n"));
1260 }
1261
1262 if (!ppd->manufacturer && ppdversion < 43)
1263 {
1264 _cupsLangPuts(stdout,
1265 _(" WARN Manufacturer required by PPD "
1266 "4.3 spec.\n"
1267 " REF: Pages 58-59, section 5.3.\n"));
1268 }
1269
1270 /*
1271 * Treat a PCFileName attribute longer than 12 characters as
1272 * a warning and not a hard error...
1273 */
1274
1275 if (ppd->pcfilename && strlen(ppd->pcfilename) > 12)
1276 {
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"));
1281 }
1282
1283 if (!ppd->shortnickname && ppdversion < 43)
1284 {
1285 _cupsLangPuts(stdout,
1286 _(" WARN ShortNickName required by PPD "
1287 "4.3 spec.\n"
1288 " REF: Pages 64-65, section 5.3.\n"));
1289 }
1290
1291 /*
1292 * Check the Protocols line and flag PJL + BCP since TBCP is
1293 * usually used with PJL...
1294 */
1295
1296 if (ppd->protocols)
1297 {
1298 if (strstr(ppd->protocols, "PJL") &&
1299 strstr(ppd->protocols, "BCP") &&
1300 !strstr(ppd->protocols, "TBCP"))
1301 {
1302 _cupsLangPuts(stdout,
1303 _(" WARN Protocols contains both PJL "
1304 "and BCP; expected TBCP.\n"
1305 " REF: Pages 78-79, section 5.7.\n"));
1306 }
1307
1308 if (strstr(ppd->protocols, "PJL") &&
1309 (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps))
1310 {
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"));
1315 }
1316 }
1317
1318 /*
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...
1322 */
1323
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 ++)
1326 {
1327 len = strlen(option->keyword);
1328
1329 for (m = 0, group2 = ppd->groups;
1330 m < ppd->num_groups;
1331 m ++, group2 ++)
1332 for (n = 0, option2 = group2->options;
1333 n < group2->num_options;
1334 n ++, option2 ++)
1335 if (option != option2 &&
1336 len < strlen(option2->keyword) &&
1337 !strncmp(option->keyword, option2->keyword, len))
1338 {
1339 _cupsLangPrintf(stdout,
1340 _(" WARN %s shares a common "
1341 "prefix with %s\n"
1342 " REF: Page 15, section "
1343 "3.2.\n"),
1344 option->keyword, option2->keyword);
1345 }
1346 }
1347 }
1348
1349 /*
1350 * cupsICCProfile
1351 */
1352
1353 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
1354 attr != NULL;
1355 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
1356 {
1357 if (attr->value)
1358 {
1359 if (attr->value[0] == '/')
1360 snprintf(pathprog, sizeof(pathprog), "%s%s", root, attr->value);
1361 else
1362 {
1363 if ((ptr = getenv("CUPS_DATADIR")) == NULL)
1364 ptr = CUPS_DATADIR;
1365
1366 if (*ptr == '/' || !*root)
1367 snprintf(pathprog, sizeof(pathprog), "%s%s/profiles/%s", root,
1368 ptr, attr->value);
1369 else
1370 snprintf(pathprog, sizeof(pathprog), "%s/%s/profiles/%s", root,
1371 ptr, attr->value);
1372 }
1373 }
1374
1375 if (!attr->value || !attr->value[0] || stat(pathprog, &statbuf))
1376 {
1377 if (verbose >= 0)
1378 _cupsLangPrintf(stdout,
1379 _(" WARN Missing cupsICCProfile "
1380 "file \"%s\"\n"),
1381 !attr->value || !attr->value[0] ? "<NULL>" :
1382 attr->value);
1383 }
1384 }
1385
1386 #ifdef __APPLE__
1387 /*
1388 * APDialogExtension
1389 */
1390
1391 for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL);
1392 attr != NULL;
1393 attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
1394 {
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>");
1399 }
1400
1401 /*
1402 * APPrinterIconPath
1403 */
1404
1405 for (attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL);
1406 attr != NULL;
1407 attr = ppdFindNextAttr(ppd, "APPrinterIconPath", NULL))
1408 {
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>");
1413 }
1414 #endif /* __APPLE__ */
1415
1416 if (verbose > 0)
1417 {
1418 if (errors)
1419 _cupsLangPrintf(stdout, _(" %d ERRORS FOUND\n"), errors);
1420 else
1421 _cupsLangPuts(stdout, _(" NO ERRORS FOUND\n"));
1422 }
1423
1424 /*
1425 * Then list the options, if "-v" was provided...
1426 */
1427
1428 if (verbose > 1)
1429 {
1430 _cupsLangPrintf(stdout,
1431 "\n"
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",
1439 ppd->landscape);
1440
1441 switch (ppd->colorspace)
1442 {
1443 case PPD_CS_CMYK :
1444 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMYK\n");
1445 break;
1446 case PPD_CS_CMY :
1447 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMY\n");
1448 break;
1449 case PPD_CS_GRAY :
1450 _cupsLangPuts(stdout, " colorspace = PPD_CS_GRAY\n");
1451 break;
1452 case PPD_CS_RGB :
1453 _cupsLangPuts(stdout, " colorspace = PPD_CS_RGB\n");
1454 break;
1455 default :
1456 _cupsLangPuts(stdout, " colorspace = <unknown>\n");
1457 break;
1458 }
1459
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);
1465
1466 _cupsLangPrintf(stdout, " lang_encoding = %s\n",
1467 ppd->lang_encoding);
1468 _cupsLangPrintf(stdout, " lang_version = %s\n",
1469 ppd->lang_version);
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",
1474 ppd->manufacturer);
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));
1481
1482 _cupsLangPrintf(stdout, " num_groups = %d\n", ppd->num_groups);
1483 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1484 {
1485 _cupsLangPrintf(stdout, " group[%d] = %s\n",
1486 j, group->text);
1487
1488 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1489 {
1490 _cupsLangPrintf(stdout,
1491 " options[%d] = %s (%s) %s %s %.0f "
1492 "(%d choices)\n",
1493 k, option->keyword, option->text, uis[option->ui],
1494 sections[option->section], option->order,
1495 option->num_choices);
1496
1497 if (!strcmp(option->keyword, "PageSize") ||
1498 !strcmp(option->keyword, "PageRegion"))
1499 {
1500 for (m = option->num_choices, choice = option->choices;
1501 m > 0;
1502 m --, choice ++)
1503 {
1504 size = ppdPageSize(ppd, choice->choice);
1505
1506 if (size == NULL)
1507 _cupsLangPrintf(stdout,
1508 " %s (%s) = ERROR",
1509 choice->choice, choice->text);
1510 else
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);
1518
1519 if (!strcmp(option->defchoice, choice->choice))
1520 _cupsLangPuts(stdout, " *\n");
1521 else
1522 _cupsLangPuts(stdout, "\n");
1523 }
1524 }
1525 else
1526 {
1527 for (m = option->num_choices, choice = option->choices;
1528 m > 0;
1529 m --, choice ++)
1530 {
1531 _cupsLangPrintf(stdout, " %s (%s)",
1532 choice->choice, choice->text);
1533
1534 if (!strcmp(option->defchoice, choice->choice))
1535 _cupsLangPuts(stdout, " *\n");
1536 else
1537 _cupsLangPuts(stdout, "\n");
1538 }
1539 }
1540 }
1541 }
1542
1543 _cupsLangPrintf(stdout, " num_profiles = %d\n",
1544 ppd->num_profiles);
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]);
1561
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",
1565 j, ppd->fonts[j]);
1566
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)");
1576 }
1577
1578 ppdClose(ppd);
1579 }
1580
1581 if (!files)
1582 usage();
1583
1584 return (status);
1585 }
1586
1587
1588 /*
1589 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1590 */
1591
1592 void
1593 check_basics(const char *filename) /* I - PPD file to check */
1594 {
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? */
1602
1603
1604 if ((fp = cupsFileOpen(filename, "r")) == NULL)
1605 return;
1606
1607 linenum = 1;
1608 col = 0;
1609 eol = EOL_NONE;
1610 mixed = 0;
1611 whitespace = 1;
1612
1613 while ((ch = cupsFileGetChar(fp)) != EOF)
1614 {
1615 if (ch == '\r' || ch == '\n')
1616 {
1617 if (ch == '\n')
1618 {
1619 if (eol == EOL_NONE)
1620 eol = EOL_LF;
1621 else if (eol != EOL_LF)
1622 mixed = 1;
1623 }
1624 else if (ch == '\r')
1625 {
1626 if (cupsFilePeekChar(fp) == '\n')
1627 {
1628 cupsFileGetChar(fp);
1629
1630 if (eol == EOL_NONE)
1631 eol = EOL_CRLF;
1632 else
1633 mixed = 1;
1634 }
1635 else if (eol == EOL_NONE)
1636 eol = EOL_CR;
1637 else
1638 mixed = 1;
1639 }
1640
1641 if (col > 0 && whitespace)
1642 _cupsLangPrintf(stdout,
1643 _(" WARN Line %d only contains whitespace!\n"),
1644 linenum);
1645
1646 linenum ++;
1647 col = 0;
1648 whitespace = 1;
1649 }
1650 else
1651 {
1652 if (ch != ' ' && ch != '\t')
1653 whitespace = 0;
1654
1655 col ++;
1656 }
1657 }
1658
1659 if (mixed)
1660 _cupsLangPuts(stdout,
1661 _(" WARN File contains a mix of CR, LF, and "
1662 "CR LF line endings!\n"));
1663
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"));
1668
1669 cupsFileClose(fp);
1670 }
1671
1672
1673 /*
1674 * 'check_constraints()' - Check UIConstraints in the PPD file.
1675 */
1676
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? */
1682 {
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 */
1688
1689
1690 prefix = warn ? " WARN " : "**FAIL**";
1691
1692 for (j = ppd->num_consts, c = ppd->consts; j > 0; j --, c ++)
1693 {
1694 option = ppdFindOption(ppd, c->option1);
1695 option2 = ppdFindOption(ppd, c->option2);
1696
1697 if (!option || !option2)
1698 {
1699 if (!warn && !errors && !verbose)
1700 _cupsLangPuts(stdout, _(" FAIL\n"));
1701
1702 if (!option)
1703 _cupsLangPrintf(stdout,
1704 _(" %s Missing option %s in "
1705 "UIConstraint \"*%s %s *%s %s\"!\n"),
1706 prefix, c->option1,
1707 c->option1, c->choice1, c->option2, c->choice2);
1708
1709 if (!option2)
1710 _cupsLangPrintf(stdout,
1711 _(" %s Missing option %s in "
1712 "UIConstraint \"*%s %s *%s %s\"!\n"),
1713 prefix, c->option2,
1714 c->option1, c->choice1, c->option2, c->choice2);
1715
1716 if (!warn)
1717 errors ++;
1718
1719 continue;
1720 }
1721
1722 if (c->choice1[0] && !ppdFindChoice(option, c->choice1))
1723 {
1724 if (!warn && !errors && !verbose)
1725 _cupsLangPuts(stdout, _(" FAIL\n"));
1726
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);
1732
1733 if (!warn)
1734 errors ++;
1735 }
1736
1737 if (c->choice2[0] && !ppdFindChoice(option2, c->choice2))
1738 {
1739 if (!warn && !errors && !verbose)
1740 _cupsLangPuts(stdout, _(" FAIL\n"));
1741
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);
1747
1748 if (!warn)
1749 errors ++;
1750 }
1751 }
1752
1753 return (errors);
1754 }
1755
1756
1757 /*
1758 * 'check_defaults()' - Check default option keywords in the PPD file.
1759 */
1760
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? */
1766 {
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 */
1771
1772
1773 prefix = warn ? " WARN " : "**FAIL**";
1774
1775 for (j = 0; j < ppd->num_attrs; j ++)
1776 {
1777 attr = ppd->attrs[j];
1778
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"))
1786 continue;
1787
1788 if (!strncmp(attr->name, "Default", 7))
1789 {
1790 if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
1791 strcmp(attr->value, "Unknown"))
1792 {
1793 /*
1794 * Check that the default option value matches a choice...
1795 */
1796
1797 for (k = 0; k < option->num_choices; k ++)
1798 if (!strcmp(option->choices[k].choice, attr->value))
1799 break;
1800
1801 if (k >= option->num_choices)
1802 {
1803 if (!warn && !errors && !verbose)
1804 _cupsLangPuts(stdout, _(" FAIL\n"));
1805
1806 if (verbose >= 0)
1807 _cupsLangPrintf(stdout,
1808 _(" %s %s %s does not exist!\n"),
1809 prefix, attr->name, attr->value);
1810
1811 if (!warn)
1812 errors ++;
1813 }
1814 }
1815 }
1816 }
1817
1818 return (errors);
1819 }
1820
1821
1822 /*
1823 * 'check_filters()' - Check filters in the PPD file.
1824 */
1825
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? */
1832 {
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 */
1842
1843
1844 prefix = warn ? " WARN " : "**FAIL**";
1845
1846 for (attr = ppdFindAttr(ppd, "cupsFilter", NULL);
1847 attr;
1848 attr = ppdFindNextAttr(ppd, "cupsFilter", NULL))
1849 {
1850 if (!attr->value ||
1851 sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
1852 program) != 4)
1853 {
1854 if (!warn && !errors && !verbose)
1855 _cupsLangPuts(stdout, _(" FAIL\n"));
1856
1857 if (verbose >= 0)
1858 _cupsLangPrintf(stdout,
1859 _(" %s Bad cupsFilter value \"%s\"!\n"),
1860 prefix, attr->value ? attr->value : "");
1861
1862 if (!warn)
1863 errors ++;
1864 }
1865 else
1866 {
1867 if (program[0] == '/')
1868 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
1869 else
1870 {
1871 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
1872 ptr = CUPS_SERVERBIN;
1873
1874 if (*ptr == '/' || !*root)
1875 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
1876 program);
1877 else
1878 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
1879 program);
1880 }
1881
1882 if (stat(pathprog, &statbuf))
1883 {
1884 if (!warn && !errors && !verbose)
1885 _cupsLangPuts(stdout, _(" FAIL\n"));
1886
1887 if (verbose >= 0)
1888 _cupsLangPrintf(stdout, _(" %s Missing cupsFilter "
1889 "file \"%s\"\n"), prefix, program);
1890
1891 if (!warn)
1892 errors ++;
1893 }
1894 }
1895 }
1896
1897 for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
1898 attr;
1899 attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
1900 {
1901 if (!attr->value ||
1902 sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
1903 program) != 4)
1904 {
1905 if (!warn && !errors && !verbose)
1906 _cupsLangPuts(stdout, _(" FAIL\n"));
1907
1908 if (verbose >= 0)
1909 _cupsLangPrintf(stdout,
1910 _(" %s Bad cupsPreFilter value \"%s\"!\n"),
1911 prefix, attr->value ? attr->value : "");
1912
1913 if (!warn)
1914 errors ++;
1915 }
1916 else
1917 {
1918 if (program[0] == '/')
1919 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
1920 else
1921 {
1922 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
1923 ptr = CUPS_SERVERBIN;
1924
1925 if (*ptr == '/' || !*root)
1926 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
1927 program);
1928 else
1929 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
1930 program);
1931 }
1932
1933 if (stat(pathprog, &statbuf))
1934 {
1935 if (!warn && !errors && !verbose)
1936 _cupsLangPuts(stdout, _(" FAIL\n"));
1937
1938 if (verbose >= 0)
1939 _cupsLangPrintf(stdout, _(" %s Missing cupsPreFilter "
1940 "file \"%s\"\n"), prefix, program);
1941
1942 if (!warn)
1943 errors ++;
1944 }
1945 }
1946 }
1947
1948 return (errors);
1949 }
1950
1951
1952 /*
1953 * 'check_translations()' - Check translations in the PPD file.
1954 */
1955
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? */
1961 {
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 */
1978
1979
1980 prefix = warn ? " WARN " : "**FAIL**";
1981
1982 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
1983 attr->value)
1984 {
1985 /*
1986 * This file contains localizations, check them...
1987 */
1988
1989 languages = strdup(attr->value);
1990 langlist = cupsArrayNew((cups_array_func_t)strcmp, NULL);
1991
1992 for (langptr = languages; *langptr;)
1993 {
1994 /*
1995 * Skip leading whitespace...
1996 */
1997
1998 while (isspace(*langptr & 255))
1999 langptr ++;
2000
2001 if (!*langptr)
2002 break;
2003
2004 /*
2005 * Find the end of this language name...
2006 */
2007
2008 for (langstart = langptr;
2009 *langptr && !isspace(*langptr & 255);
2010 langptr ++);
2011
2012 if (*langptr)
2013 *langptr++ = '\0';
2014
2015 j = strlen(langstart);
2016 if (j != 2 && j != 5)
2017 {
2018 if (!warn && !errors && !verbose)
2019 _cupsLangPuts(stdout, _(" FAIL\n"));
2020
2021 if (verbose >= 0)
2022 _cupsLangPrintf(stdout,
2023 _(" %s Bad language \"%s\"!\n"),
2024 prefix, langstart);
2025
2026 if (!warn)
2027 errors ++;
2028
2029 continue;
2030 }
2031
2032 cupsArrayAdd(langlist, langstart);
2033
2034 strlcpy(ll, langstart, sizeof(ll));
2035
2036 /*
2037 * Loop through all options and choices...
2038 */
2039
2040 for (option = ppdFirstOption(ppd);
2041 option;
2042 option = ppdNextOption(ppd))
2043 {
2044 snprintf(keyword, sizeof(keyword), "%s.Translation", langstart);
2045 snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll);
2046
2047 if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL &&
2048 (attr = ppdFindAttr(ppd, llkeyword, option->keyword)) == NULL)
2049 {
2050 if (!warn && !errors && !verbose)
2051 _cupsLangPuts(stdout, _(" FAIL\n"));
2052
2053 if (verbose >= 0)
2054 _cupsLangPrintf(stdout,
2055 _(" %s Missing \"%s\" translation "
2056 "string for option %s!\n"),
2057 prefix, langstart, option->keyword);
2058
2059 if (!warn)
2060 errors ++;
2061 }
2062 else if (!valid_utf8(attr->text))
2063 {
2064 if (!warn && !errors && !verbose)
2065 _cupsLangPuts(stdout, _(" FAIL\n"));
2066
2067 if (verbose >= 0)
2068 _cupsLangPrintf(stdout,
2069 _(" %s Bad UTF-8 \"%s\" translation "
2070 "string for option %s!\n"),
2071 prefix, langstart, option->keyword);
2072
2073 if (!warn)
2074 errors ++;
2075 }
2076
2077 snprintf(keyword, sizeof(keyword), "%s.%s", langstart,
2078 option->keyword);
2079 snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll,
2080 option->keyword);
2081
2082 for (j = 0; j < option->num_choices; j ++)
2083 {
2084 if (!strcasecmp(option->choices[j].choice, "Custom") &&
2085 (coption = ppdFindCustomOption(ppd,
2086 option->keyword)) != NULL)
2087 {
2088 snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
2089 langstart, option->keyword);
2090
2091 if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
2092 !valid_utf8(attr->text))
2093 {
2094 if (!warn && !errors && !verbose)
2095 _cupsLangPuts(stdout, _(" FAIL\n"));
2096
2097 if (verbose >= 0)
2098 _cupsLangPrintf(stdout,
2099 _(" %s Bad UTF-8 \"%s\" "
2100 "translation string for option %s, "
2101 "choice %s!\n"),
2102 prefix, langstart,
2103 ckeyword + 1 + strlen(langstart),
2104 "True");
2105
2106 if (!warn)
2107 errors ++;
2108 }
2109
2110 if (strcasecmp(option->keyword, "PageSize"))
2111 {
2112 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
2113 cparam;
2114 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
2115 {
2116 snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
2117 langstart, option->keyword);
2118 snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s",
2119 ll, option->keyword);
2120
2121 if ((attr = ppdFindAttr(ppd, ckeyword,
2122 cparam->name)) == NULL &&
2123 (attr = ppdFindAttr(ppd, cllkeyword,
2124 cparam->name)) == NULL)
2125 {
2126 if (!warn && !errors && !verbose)
2127 _cupsLangPuts(stdout, _(" FAIL\n"));
2128
2129 if (verbose >= 0)
2130 _cupsLangPrintf(stdout,
2131 _(" %s Missing \"%s\" "
2132 "translation string for option %s, "
2133 "choice %s!\n"),
2134 prefix, langstart,
2135 ckeyword + 1 + strlen(langstart),
2136 cparam->name);
2137
2138 if (!warn)
2139 errors ++;
2140 }
2141 else if (!valid_utf8(attr->text))
2142 {
2143 if (!warn && !errors && !verbose)
2144 _cupsLangPuts(stdout, _(" FAIL\n"));
2145
2146 if (verbose >= 0)
2147 _cupsLangPrintf(stdout,
2148 _(" %s Bad UTF-8 \"%s\" "
2149 "translation string for option %s, "
2150 "choice %s!\n"),
2151 prefix, langstart,
2152 ckeyword + 1 + strlen(langstart),
2153 cparam->name);
2154
2155 if (!warn)
2156 errors ++;
2157 }
2158 }
2159 }
2160 }
2161 else if ((attr = ppdFindAttr(ppd, keyword,
2162 option->choices[j].choice)) == NULL &&
2163 (attr = ppdFindAttr(ppd, llkeyword,
2164 option->choices[j].choice)) == NULL)
2165 {
2166 if (!warn && !errors && !verbose)
2167 _cupsLangPuts(stdout, _(" FAIL\n"));
2168
2169 if (verbose >= 0)
2170 _cupsLangPrintf(stdout,
2171 _(" %s Missing \"%s\" "
2172 "translation string for option %s, "
2173 "choice %s!\n"),
2174 prefix, langstart, option->keyword,
2175 option->choices[j].choice);
2176
2177 if (!warn)
2178 errors ++;
2179 }
2180 else if (!valid_utf8(attr->text))
2181 {
2182 if (!warn && !errors && !verbose)
2183 _cupsLangPuts(stdout, _(" FAIL\n"));
2184
2185 if (verbose >= 0)
2186 _cupsLangPrintf(stdout,
2187 _(" %s Bad UTF-8 \"%s\" "
2188 "translation string for option %s, "
2189 "choice %s!\n"),
2190 prefix, langstart, option->keyword,
2191 option->choices[j].choice);
2192
2193 if (!warn)
2194 errors ++;
2195 }
2196 }
2197 }
2198 }
2199
2200 /*
2201 * Verify that we have the base language for each localized one...
2202 */
2203
2204 for (langptr = (char *)cupsArrayFirst(langlist);
2205 langptr;
2206 langptr = (char *)cupsArrayNext(langlist))
2207 if (langptr[2])
2208 {
2209 /*
2210 * Lookup the base language...
2211 */
2212
2213 cupsArraySave(langlist);
2214
2215 strlcpy(ll, langptr, sizeof(ll));
2216
2217 if (!cupsArrayFind(langlist, ll) && strcmp(ll, "zh"))
2218 {
2219 if (!warn && !errors && !verbose)
2220 _cupsLangPuts(stdout, _(" FAIL\n"));
2221
2222 if (verbose >= 0)
2223 _cupsLangPrintf(stdout,
2224 _(" %s No base translation \"%s\" "
2225 "is included in file!\n"), prefix, ll);
2226
2227 if (!warn)
2228 errors ++;
2229 }
2230
2231 cupsArrayRestore(langlist);
2232 }
2233
2234 /*
2235 * Free memory used for the languages...
2236 */
2237
2238 cupsArrayDelete(langlist);
2239 free(languages);
2240 }
2241
2242 return (errors);
2243 }
2244
2245
2246 /*
2247 * 'show_conflicts()' - Show option conflicts in a PPD file.
2248 */
2249
2250 void
2251 show_conflicts(ppd_file_t *ppd) /* I - PPD to check */
2252 {
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 */
2257
2258
2259 /*
2260 * Loop through all of the UI constraints and report any options
2261 * that conflict...
2262 */
2263
2264 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
2265 {
2266 /*
2267 * Grab pointers to the first option...
2268 */
2269
2270 o1 = ppdFindOption(ppd, c->option1);
2271
2272 if (o1 == NULL)
2273 continue;
2274 else if (c->choice1[0] != '\0')
2275 {
2276 /*
2277 * This constraint maps to a specific choice.
2278 */
2279
2280 c1 = ppdFindChoice(o1, c->choice1);
2281 }
2282 else
2283 {
2284 /*
2285 * This constraint applies to any choice for this option.
2286 */
2287
2288 for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
2289 if (c1->marked)
2290 break;
2291
2292 if (j == 0 ||
2293 !strcasecmp(c1->choice, "None") ||
2294 !strcasecmp(c1->choice, "Off") ||
2295 !strcasecmp(c1->choice, "False"))
2296 c1 = NULL;
2297 }
2298
2299 /*
2300 * Grab pointers to the second option...
2301 */
2302
2303 o2 = ppdFindOption(ppd, c->option2);
2304
2305 if (o2 == NULL)
2306 continue;
2307 else if (c->choice2[0] != '\0')
2308 {
2309 /*
2310 * This constraint maps to a specific choice.
2311 */
2312
2313 c2 = ppdFindChoice(o2, c->choice2);
2314 }
2315 else
2316 {
2317 /*
2318 * This constraint applies to any choice for this option.
2319 */
2320
2321 for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
2322 if (c2->marked)
2323 break;
2324
2325 if (j == 0 ||
2326 !strcasecmp(c2->choice, "None") ||
2327 !strcasecmp(c2->choice, "Off") ||
2328 !strcasecmp(c2->choice, "False"))
2329 c2 = NULL;
2330 }
2331
2332 /*
2333 * If both options are marked then there is a conflict...
2334 */
2335
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);
2342 }
2343 }
2344
2345
2346 /*
2347 * 'usage()' - Show program usage...
2348 */
2349
2350 void
2351 usage(void)
2352 {
2353 _cupsLangPuts(stdout,
2354 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
2355 "[... filenameN.ppd[.gz]]\n"
2356 " program | cupstestppd [options] -\n"
2357 "\n"
2358 "Options:\n"
2359 "\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"));
2367
2368 exit(ERROR_USAGE);
2369 }
2370
2371
2372 /*
2373 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
2374 */
2375
2376 int /* O - 1 if valid, 0 if not */
2377 valid_utf8(const char *s) /* I - String to check */
2378 {
2379 while (*s)
2380 {
2381 if (*s & 0x80)
2382 {
2383 /*
2384 * Check for valid UTF-8 sequence...
2385 */
2386
2387 if ((*s & 0xc0) == 0x80)
2388 return (0); /* Illegal suffix byte */
2389 else if ((*s & 0xe0) == 0xc0)
2390 {
2391 /*
2392 * 2-byte sequence...
2393 */
2394
2395 s ++;
2396
2397 if ((*s & 0xc0) != 0x80)
2398 return (0); /* Missing suffix byte */
2399 }
2400 else if ((*s & 0xf0) == 0xe0)
2401 {
2402 /*
2403 * 3-byte sequence...
2404 */
2405
2406 s ++;
2407
2408 if ((*s & 0xc0) != 0x80)
2409 return (0); /* Missing suffix byte */
2410
2411 s ++;
2412
2413 if ((*s & 0xc0) != 0x80)
2414 return (0); /* Missing suffix byte */
2415 }
2416 else if ((*s & 0xf8) == 0xf0)
2417 {
2418 /*
2419 * 4-byte sequence...
2420 */
2421
2422 s ++;
2423
2424 if ((*s & 0xc0) != 0x80)
2425 return (0); /* Missing suffix byte */
2426
2427 s ++;
2428
2429 if ((*s & 0xc0) != 0x80)
2430 return (0); /* Missing suffix byte */
2431
2432 s ++;
2433
2434 if ((*s & 0xc0) != 0x80)
2435 return (0); /* Missing suffix byte */
2436 }
2437 else
2438 return (0); /* Bad sequence */
2439 }
2440
2441 s ++;
2442 }
2443
2444 return (1);
2445 }
2446
2447
2448 /*
2449 * End of "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $".
2450 */