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