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