1/* 2 * "$Id: cupstestppd.c 11560 2014-02-06 20:10:19Z msweet $" 3 * 4 * PPD test program for CUPS. 5 * 6 * Copyright 2007-2013 by Apple Inc. 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 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/". 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 * 21 * main() - Main entry for test program. 22 * check_basics() - Check for CR LF, mixed line endings, and blank 23 * lines. 24 * check_constraints() - Check UIConstraints in the PPD file. 25 * check_case() - Check that there are no duplicate groups, options, 26 * or choices that differ only by case. 27 * check_defaults() - Check default option keywords in the PPD file. 28 * check_duplex() - Check duplex keywords in the PPD file. 29 * check_filters() - Check filters in the PPD file. 30 * check_profiles() - Check ICC color profiles in the PPD file. 31 * check_sizes() - Check media sizes in the PPD file. 32 * check_translations() - Check translations in the PPD file. 33 * show_conflicts() - Show option conflicts in a PPD file. 34 * test_raster() - Test PostScript commands for raster printers. 35 * usage() - Show program usage. 36 * valid_path() - Check whether a path has the correct capitalization. 37 * valid_utf8() - Check whether a string contains valid UTF-8 text. 38 */ 39 40/* 41 * Include necessary headers... 42 */ 43 44#include <cups/cups-private.h> 45#include <cups/dir.h> 46#include <cups/ppd-private.h> 47#include <cups/raster.h> 48#include <math.h> 49#ifdef WIN32 50# define X_OK 0 51#endif /* WIN32 */ 52 53 54/* 55 * Error warning overrides... 56 */ 57 58enum 59{ 60 WARN_NONE = 0, 61 WARN_CONSTRAINTS = 1, 62 WARN_DEFAULTS = 2, 63 WARN_FILTERS = 4, 64 WARN_PROFILES = 8, 65 WARN_TRANSLATIONS = 16, 66 WARN_DUPLEX = 32, 67 WARN_SIZES = 64, 68 WARN_FILENAME = 128, 69 WARN_ALL = 255 70}; 71 72 73/* 74 * Error codes... 75 */ 76 77enum 78{ 79 ERROR_NONE = 0, 80 ERROR_USAGE, 81 ERROR_FILE_OPEN, 82 ERROR_PPD_FORMAT, 83 ERROR_CONFORMANCE 84}; 85 86 87/* 88 * Line endings... 89 */ 90 91enum 92{ 93 EOL_NONE = 0, 94 EOL_CR, 95 EOL_LF, 96 EOL_CRLF 97}; 98 99 100/* 101 * File permissions... 102 */ 103 104#define MODE_WRITE 0022 /* Group/other write */ 105#define MODE_MASK 0555 /* Owner/group/other read+exec/search */ 106#define MODE_DATAFILE 0444 /* Owner/group/other read */ 107#define MODE_DIRECTORY 0555 /* Owner/group/other read+search */ 108#define MODE_PROGRAM 0555 /* Owner/group/other read+exec */ 109 110 111/* 112 * Local functions... 113 */ 114 115static void check_basics(const char *filename); 116static int check_constraints(ppd_file_t *ppd, int errors, int verbose, 117 int warn); 118static int check_case(ppd_file_t *ppd, int errors, int verbose); 119static int check_defaults(ppd_file_t *ppd, int errors, int verbose, 120 int warn); 121static int check_duplex(ppd_file_t *ppd, int errors, int verbose, 122 int warn); 123static int check_filters(ppd_file_t *ppd, const char *root, int errors, 124 int verbose, int warn); 125static int check_profiles(ppd_file_t *ppd, const char *root, int errors, 126 int verbose, int warn); 127static int check_sizes(ppd_file_t *ppd, int errors, int verbose, int warn); 128static int check_translations(ppd_file_t *ppd, int errors, int verbose, 129 int warn); 130static void show_conflicts(ppd_file_t *ppd, const char *prefix); 131static int test_raster(ppd_file_t *ppd, int verbose); 132static void usage(void) __attribute__((noreturn)); 133static int valid_path(const char *keyword, const char *path, int errors, 134 int verbose, int warn); 135static int valid_utf8(const char *s); 136 137 138/* 139 * 'main()' - Main entry for test program. 140 */ 141 142int /* O - Exit status */ 143main(int argc, /* I - Number of command-line args */ 144 char *argv[]) /* I - Command-line arguments */ 145{ 146 int i, j, k, m, n; /* Looping vars */ 147 size_t len; /* Length of option name */ 148 char *opt; /* Option character */ 149 const char *ptr; /* Pointer into string */ 150 cups_file_t *fp; /* PPD file */ 151 int files; /* Number of files */ 152 int verbose; /* Want verbose output? */ 153 int warn; /* Which errors to just warn about */ 154 int ignore; /* Which errors to ignore */ 155 int status; /* Exit status */ 156 int errors; /* Number of conformance errors */ 157 int ppdversion; /* PPD spec version in PPD file */ 158 ppd_status_t error; /* Status of ppdOpen*() */ 159 int line; /* Line number for error */ 160 char *root; /* Root directory */ 161 int xdpi, /* X resolution */ 162 ydpi; /* Y resolution */ 163 ppd_file_t *ppd; /* PPD file record */ 164 ppd_attr_t *attr; /* PPD attribute */ 165 ppd_size_t *size; /* Size record */ 166 ppd_group_t *group; /* UI group */ 167 ppd_option_t *option; /* Standard UI option */ 168 ppd_group_t *group2; /* UI group */ 169 ppd_option_t *option2; /* Standard UI option */ 170 ppd_choice_t *choice; /* Standard UI option choice */ 171 struct lconv *loc; /* Locale data */ 172 static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" }; 173 static char *sections[] = { "ANY", "DOCUMENT", "EXIT", 174 "JCL", "PAGE", "PROLOG" }; 175 176 177 _cupsSetLocale(argv); 178 loc = localeconv(); 179 180 /* 181 * Display PPD files for each file listed on the command-line... 182 */ 183 184 ppdSetConformance(PPD_CONFORM_STRICT); 185 186 verbose = 0; 187 ppd = NULL; 188 files = 0; 189 status = ERROR_NONE; 190 root = ""; 191 warn = WARN_NONE; 192 ignore = WARN_NONE; 193 194 for (i = 1; i < argc; i ++) 195 if (argv[i][0] == '-' && argv[i][1]) 196 { 197 for (opt = argv[i] + 1; *opt; opt ++) 198 switch (*opt) 199 { 200 case 'I' : /* Ignore errors */ 201 i ++; 202 203 if (i >= argc) 204 usage(); 205 206 if (!strcmp(argv[i], "none")) 207 ignore = WARN_NONE; 208 else if (!strcmp(argv[i], "filename")) 209 ignore |= WARN_FILENAME; 210 else if (!strcmp(argv[i], "filters")) 211 ignore |= WARN_FILTERS; 212 else if (!strcmp(argv[i], "profiles")) 213 ignore |= WARN_PROFILES; 214 else if (!strcmp(argv[i], "all")) 215 ignore = WARN_FILTERS | WARN_PROFILES; 216 else 217 usage(); 218 break; 219 220 case 'R' : /* Alternate root directory */ 221 i ++; 222 223 if (i >= argc) 224 usage(); 225 226 root = argv[i]; 227 break; 228 229 case 'W' : /* Turn errors into warnings */ 230 i ++; 231 232 if (i >= argc) 233 usage(); 234 235 if (!strcmp(argv[i], "none")) 236 warn = WARN_NONE; 237 else if (!strcmp(argv[i], "constraints")) 238 warn |= WARN_CONSTRAINTS; 239 else if (!strcmp(argv[i], "defaults")) 240 warn |= WARN_DEFAULTS; 241 else if (!strcmp(argv[i], "duplex")) 242 warn |= WARN_DUPLEX; 243 else if (!strcmp(argv[i], "filters")) 244 warn |= WARN_FILTERS; 245 else if (!strcmp(argv[i], "profiles")) 246 warn |= WARN_PROFILES; 247 else if (!strcmp(argv[i], "sizes")) 248 warn |= WARN_SIZES; 249 else if (!strcmp(argv[i], "translations")) 250 warn |= WARN_TRANSLATIONS; 251 else if (!strcmp(argv[i], "all")) 252 warn = WARN_ALL; 253 else 254 usage(); 255 break; 256 257 case 'q' : /* Quiet mode */ 258 if (verbose > 0) 259 { 260 _cupsLangPuts(stderr, 261 _("cupstestppd: The -q option is incompatible " 262 "with the -v option.")); 263 return (1); 264 } 265 266 verbose --; 267 break; 268 269 case 'r' : /* Relaxed mode */ 270 ppdSetConformance(PPD_CONFORM_RELAXED); 271 break; 272 273 case 'v' : /* Verbose mode */ 274 if (verbose < 0) 275 { 276 _cupsLangPuts(stderr, 277 _("cupstestppd: The -v option is incompatible " 278 "with the -q option.")); 279 return (1); 280 } 281 282 verbose ++; 283 break; 284 285 default : 286 usage(); 287 break; 288 } 289 } 290 else 291 { 292 /* 293 * Open the PPD file... 294 */ 295 296 if (files && verbose >= 0) 297 puts(""); 298 299 files ++; 300 301 if (argv[i][0] == '-') 302 { 303 /* 304 * Read from stdin... 305 */ 306 307 ppd = _ppdOpen(cupsFileStdin(), _PPD_LOCALIZATION_ALL); 308 309 if (verbose >= 0) 310 printf("%s:", (ppd && ppd->pcfilename) ? ppd->pcfilename : "(stdin)"); 311 } 312 else 313 { 314 /* 315 * Read from a file... 316 */ 317 318 if (verbose >= 0) 319 printf("%s:", argv[i]); 320 321 if ((fp = cupsFileOpen(argv[i], "r")) != NULL) 322 { 323 ppd = _ppdOpen(fp, _PPD_LOCALIZATION_ALL); 324 cupsFileClose(fp); 325 } 326 else 327 { 328 status = ERROR_FILE_OPEN; 329 330 if (verbose >= 0) 331 { 332 _cupsLangPuts(stdout, _(" FAIL")); 333 _cupsLangPrintf(stdout, 334 _(" **FAIL** Unable to open PPD file - %s on " 335 "line %d."), strerror(errno), 0); 336 continue; 337 } 338 } 339 } 340 341 if (ppd == NULL) 342 { 343 error = ppdLastError(&line); 344 345 if (error <= PPD_ALLOC_ERROR) 346 { 347 status = ERROR_FILE_OPEN; 348 349 if (verbose >= 0) 350 { 351 _cupsLangPuts(stdout, _(" FAIL")); 352 _cupsLangPrintf(stdout, 353 _(" **FAIL** Unable to open PPD file - %s on " 354 "line %d."), strerror(errno), 0); 355 } 356 } 357 else 358 { 359 status = ERROR_PPD_FORMAT; 360 361 if (verbose >= 0) 362 { 363 _cupsLangPuts(stdout, _(" FAIL")); 364 _cupsLangPrintf(stdout, 365 _(" **FAIL** Unable to open PPD file - " 366 "%s on line %d."), 367 ppdErrorString(error), line); 368 369 switch (error) 370 { 371 case PPD_MISSING_PPDADOBE4 : 372 _cupsLangPuts(stdout, 373 _(" REF: Page 42, section " 374 "5.2.")); 375 break; 376 case PPD_MISSING_VALUE : 377 _cupsLangPuts(stdout, 378 _(" REF: Page 20, section " 379 "3.4.")); 380 break; 381 case PPD_BAD_OPEN_GROUP : 382 case PPD_NESTED_OPEN_GROUP : 383 _cupsLangPuts(stdout, 384 _(" REF: Pages 45-46, section " 385 "5.2.")); 386 break; 387 case PPD_BAD_OPEN_UI : 388 case PPD_NESTED_OPEN_UI : 389 _cupsLangPuts(stdout, 390 _(" REF: Pages 42-45, section " 391 "5.2.")); 392 break; 393 case PPD_BAD_ORDER_DEPENDENCY : 394 _cupsLangPuts(stdout, 395 _(" REF: Pages 48-49, section " 396 "5.2.")); 397 break; 398 case PPD_BAD_UI_CONSTRAINTS : 399 _cupsLangPuts(stdout, 400 _(" REF: Pages 52-54, section " 401 "5.2.")); 402 break; 403 case PPD_MISSING_ASTERISK : 404 _cupsLangPuts(stdout, 405 _(" REF: Page 15, section " 406 "3.2.")); 407 break; 408 case PPD_LINE_TOO_LONG : 409 _cupsLangPuts(stdout, 410 _(" REF: Page 15, section " 411 "3.1.")); 412 break; 413 case PPD_ILLEGAL_CHARACTER : 414 _cupsLangPuts(stdout, 415 _(" REF: Page 15, section " 416 "3.1.")); 417 break; 418 case PPD_ILLEGAL_MAIN_KEYWORD : 419 _cupsLangPuts(stdout, 420 _(" REF: Pages 16-17, section " 421 "3.2.")); 422 break; 423 case PPD_ILLEGAL_OPTION_KEYWORD : 424 _cupsLangPuts(stdout, 425 _(" REF: Page 19, section " 426 "3.3.")); 427 break; 428 case PPD_ILLEGAL_TRANSLATION : 429 _cupsLangPuts(stdout, 430 _(" REF: Page 27, section " 431 "3.5.")); 432 break; 433 default : 434 break; 435 } 436 437 check_basics(argv[i]); 438 } 439 } 440 441 continue; 442 } 443 444 /* 445 * Show the header and then perform basic conformance tests (limited 446 * only by what the CUPS PPD functions actually load...) 447 */ 448 449 errors = 0; 450 ppdversion = 43; 451 452 if (verbose > 0) 453 _cupsLangPuts(stdout, 454 _("\n DETAILED CONFORMANCE TEST RESULTS")); 455 456 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL && 457 attr->value) 458 ppdversion = (int)(10 * _cupsStrScand(attr->value, NULL, loc) + 0.5); 459 460 if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL) 461 { 462 do 463 { 464 if (strstr(attr->value, "application/vnd.cups-raster")) 465 { 466 if (!test_raster(ppd, verbose)) 467 errors ++; 468 break; 469 } 470 } 471 while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL); 472 } 473 else 474 { 475 for (j = 0; j < ppd->num_filters; j ++) 476 if (strstr(ppd->filters[j], "application/vnd.cups-raster")) 477 { 478 if (!test_raster(ppd, verbose)) 479 errors ++; 480 break; 481 } 482 } 483 484 /* 485 * Look for default keywords with no matching option... 486 */ 487 488 if (!(warn & WARN_DEFAULTS)) 489 errors = check_defaults(ppd, errors, verbose, 0); 490 491 if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL) 492 { 493 if (verbose >= 0) 494 { 495 if (!errors && !verbose) 496 _cupsLangPuts(stdout, _(" FAIL")); 497 498 _cupsLangPuts(stdout, 499 _(" **FAIL** REQUIRED DefaultImageableArea\n" 500 " REF: Page 102, section 5.15.")); 501 } 502 503 errors ++; 504 } 505 else if (ppdPageSize(ppd, attr->value) == NULL && 506 strcmp(attr->value, "Unknown")) 507 { 508 if (verbose >= 0) 509 { 510 if (!errors && !verbose) 511 _cupsLangPuts(stdout, _(" FAIL")); 512 513 _cupsLangPrintf(stdout, 514 _(" **FAIL** Bad DefaultImageableArea %s\n" 515 " REF: Page 102, section 5.15."), 516 attr->value); 517 } 518 519 errors ++; 520 } 521 else 522 { 523 if (verbose > 0) 524 _cupsLangPuts(stdout, _(" PASS DefaultImageableArea")); 525 } 526 527 if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL) 528 { 529 if (verbose >= 0) 530 { 531 if (!errors && !verbose) 532 _cupsLangPuts(stdout, _(" FAIL")); 533 534 _cupsLangPuts(stdout, 535 _(" **FAIL** REQUIRED DefaultPaperDimension\n" 536 " REF: Page 103, section 5.15.")); 537 } 538 539 errors ++; 540 } 541 else if (ppdPageSize(ppd, attr->value) == NULL && 542 strcmp(attr->value, "Unknown")) 543 { 544 if (verbose >= 0) 545 { 546 if (!errors && !verbose) 547 _cupsLangPuts(stdout, _(" FAIL")); 548 549 _cupsLangPrintf(stdout, 550 _(" **FAIL** Bad DefaultPaperDimension %s\n" 551 " REF: Page 103, section 5.15."), 552 attr->value); 553 } 554 555 errors ++; 556 } 557 else if (verbose > 0) 558 _cupsLangPuts(stdout, _(" PASS DefaultPaperDimension")); 559 560 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) 561 for (k = 0, option = group->options; 562 k < group->num_options; 563 k ++, option ++) 564 { 565 /* 566 * Verify that we have a default choice... 567 */ 568 569 if (option->defchoice[0]) 570 { 571 if (ppdFindChoice(option, option->defchoice) == NULL && 572 strcmp(option->defchoice, "Unknown")) 573 { 574 if (verbose >= 0) 575 { 576 if (!errors && !verbose) 577 _cupsLangPuts(stdout, _(" FAIL")); 578 579 _cupsLangPrintf(stdout, 580 _(" **FAIL** Bad Default%s %s\n" 581 " REF: Page 40, section 4.5."), 582 option->keyword, option->defchoice); 583 } 584 585 errors ++; 586 } 587 else if (verbose > 0) 588 _cupsLangPrintf(stdout, 589 _(" PASS Default%s"), 590 option->keyword); 591 } 592 else 593 { 594 if (verbose >= 0) 595 { 596 if (!errors && !verbose) 597 _cupsLangPuts(stdout, _(" FAIL")); 598 599 _cupsLangPrintf(stdout, 600 _(" **FAIL** REQUIRED Default%s\n" 601 " REF: Page 40, section 4.5."), 602 option->keyword); 603 } 604 605 errors ++; 606 } 607 } 608 609 if ((attr = ppdFindAttr(ppd, "FileVersion", NULL)) != NULL) 610 { 611 for (ptr = attr->value; *ptr; ptr ++) 612 if (!isdigit(*ptr & 255) && *ptr != '.') 613 break; 614 615 if (*ptr) 616 { 617 if (verbose >= 0) 618 { 619 if (!errors && !verbose) 620 _cupsLangPuts(stdout, _(" FAIL")); 621 622 _cupsLangPrintf(stdout, 623 _(" **FAIL** Bad FileVersion \"%s\"\n" 624 " REF: Page 56, section 5.3."), 625 attr->value); 626 } 627 628 errors ++; 629 } 630 else if (verbose > 0) 631 _cupsLangPuts(stdout, _(" PASS FileVersion")); 632 } 633 else 634 { 635 if (verbose >= 0) 636 { 637 if (!errors && !verbose) 638 _cupsLangPuts(stdout, _(" FAIL")); 639 640 _cupsLangPuts(stdout, 641 _(" **FAIL** REQUIRED FileVersion\n" 642 " REF: Page 56, section 5.3.")); 643 } 644 645 errors ++; 646 } 647 648 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL) 649 { 650 ptr = attr->value; 651 if (*ptr == '4' && ptr[1] == '.') 652 { 653 654 for (ptr += 2; *ptr; ptr ++) 655 if (!isdigit(*ptr & 255)) 656 break; 657 } 658 659 if (*ptr) 660 { 661 if (verbose >= 0) 662 { 663 if (!errors && !verbose) 664 _cupsLangPuts(stdout, _(" FAIL")); 665 666 _cupsLangPrintf(stdout, 667 _(" **FAIL** Bad FormatVersion \"%s\"\n" 668 " REF: Page 56, section 5.3."), 669 attr->value); 670 } 671 672 errors ++; 673 } 674 else if (verbose > 0) 675 _cupsLangPuts(stdout, _(" PASS FormatVersion")); 676 } 677 else 678 { 679 if (verbose >= 0) 680 { 681 if (!errors && !verbose) 682 _cupsLangPuts(stdout, _(" FAIL")); 683 684 _cupsLangPuts(stdout, 685 _(" **FAIL** REQUIRED FormatVersion\n" 686 " REF: Page 56, section 5.3.")); 687 } 688 689 errors ++; 690 } 691 692 if (ppd->lang_encoding != NULL) 693 { 694 if (verbose > 0) 695 _cupsLangPuts(stdout, _(" PASS LanguageEncoding")); 696 } 697 else if (ppdversion > 40) 698 { 699 if (verbose >= 0) 700 { 701 if (!errors && !verbose) 702 _cupsLangPuts(stdout, _(" FAIL")); 703 704 _cupsLangPuts(stdout, 705 _(" **FAIL** REQUIRED LanguageEncoding\n" 706 " REF: Pages 56-57, section 5.3.")); 707 } 708 709 errors ++; 710 } 711 712 if (ppd->lang_version != NULL) 713 { 714 if (verbose > 0) 715 _cupsLangPuts(stdout, _(" PASS LanguageVersion")); 716 } 717 else 718 { 719 if (verbose >= 0) 720 { 721 if (!errors && !verbose) 722 _cupsLangPuts(stdout, _(" FAIL")); 723 724 _cupsLangPuts(stdout, 725 _(" **FAIL** REQUIRED LanguageVersion\n" 726 " REF: Pages 57-58, section 5.3.")); 727 } 728 729 errors ++; 730 } 731 732 if (ppd->manufacturer != NULL) 733 { 734 if (!_cups_strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) || 735 !_cups_strncasecmp(ppd->manufacturer, "Hewlett Packard", 15)) 736 { 737 if (verbose >= 0) 738 { 739 if (!errors && !verbose) 740 _cupsLangPuts(stdout, _(" FAIL")); 741 742 _cupsLangPrintf(stdout, 743 _(" **FAIL** Bad Manufacturer (should be " 744 "\"%s\")\n" 745 " REF: Page 211, table D.1."), 746 "HP"); 747 } 748 749 errors ++; 750 } 751 else if (!_cups_strncasecmp(ppd->manufacturer, "OkiData", 7) || 752 !_cups_strncasecmp(ppd->manufacturer, "Oki Data", 8)) 753 { 754 if (verbose >= 0) 755 { 756 if (!errors && !verbose) 757 _cupsLangPuts(stdout, _(" FAIL")); 758 759 _cupsLangPrintf(stdout, 760 _(" **FAIL** Bad Manufacturer (should be " 761 "\"%s\")\n" 762 " REF: Page 211, table D.1."), 763 "Oki"); 764 } 765 766 errors ++; 767 } 768 else if (verbose > 0) 769 _cupsLangPuts(stdout, _(" PASS Manufacturer")); 770 } 771 else if (ppdversion >= 43) 772 { 773 if (verbose >= 0) 774 { 775 if (!errors && !verbose) 776 _cupsLangPuts(stdout, _(" FAIL")); 777 778 _cupsLangPuts(stdout, 779 _(" **FAIL** REQUIRED Manufacturer\n" 780 " REF: Pages 58-59, section 5.3.")); 781 } 782 783 errors ++; 784 } 785 786 if (ppd->modelname != NULL) 787 { 788 for (ptr = ppd->modelname; *ptr; ptr ++) 789 if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr)) 790 break; 791 792 if (*ptr) 793 { 794 if (verbose >= 0) 795 { 796 if (!errors && !verbose) 797 _cupsLangPuts(stdout, _(" FAIL")); 798 799 _cupsLangPrintf(stdout, 800 _(" **FAIL** Bad ModelName - \"%c\" not " 801 "allowed in string.\n" 802 " REF: Pages 59-60, section 5.3."), 803 *ptr); 804 } 805 806 errors ++; 807 } 808 else if (verbose > 0) 809 _cupsLangPuts(stdout, _(" PASS ModelName")); 810 } 811 else 812 { 813 if (verbose >= 0) 814 { 815 if (!errors && !verbose) 816 _cupsLangPuts(stdout, _(" FAIL")); 817 818 _cupsLangPuts(stdout, 819 _(" **FAIL** REQUIRED ModelName\n" 820 " REF: Pages 59-60, section 5.3.")); 821 } 822 823 errors ++; 824 } 825 826 if (ppd->nickname != NULL) 827 { 828 if (verbose > 0) 829 _cupsLangPuts(stdout, _(" PASS NickName")); 830 } 831 else 832 { 833 if (verbose >= 0) 834 { 835 if (!errors && !verbose) 836 _cupsLangPuts(stdout, _(" FAIL")); 837 838 _cupsLangPuts(stdout, 839 _(" **FAIL** REQUIRED NickName\n" 840 " REF: Page 60, section 5.3.")); 841 } 842 843 errors ++; 844 } 845 846 if (ppdFindOption(ppd, "PageSize") != NULL) 847 { 848 if (verbose > 0) 849 _cupsLangPuts(stdout, _(" PASS PageSize")); 850 } 851 else 852 { 853 if (verbose >= 0) 854 { 855 if (!errors && !verbose) 856 _cupsLangPuts(stdout, _(" FAIL")); 857 858 _cupsLangPuts(stdout, 859 _(" **FAIL** REQUIRED PageSize\n" 860 " REF: Pages 99-100, section 5.14.")); 861 } 862 863 errors ++; 864 } 865 866 if (ppdFindOption(ppd, "PageRegion") != NULL) 867 { 868 if (verbose > 0) 869 _cupsLangPuts(stdout, _(" PASS PageRegion")); 870 } 871 else 872 { 873 if (verbose >= 0) 874 { 875 if (!errors && !verbose) 876 _cupsLangPuts(stdout, _(" FAIL")); 877 878 _cupsLangPuts(stdout, 879 _(" **FAIL** REQUIRED PageRegion\n" 880 " REF: Page 100, section 5.14.")); 881 } 882 883 errors ++; 884 } 885 886 if (ppd->pcfilename != NULL) 887 { 888 if (verbose > 0) 889 _cupsLangPuts(stdout, _(" PASS PCFileName")); 890 } 891 else if (!(ignore & WARN_FILENAME)) 892 { 893 if (verbose >= 0) 894 { 895 if (!errors && !verbose) 896 _cupsLangPuts(stdout, _(" FAIL")); 897 898 _cupsLangPuts(stdout, 899 _(" **FAIL** REQUIRED PCFileName\n" 900 " REF: Pages 61-62, section 5.3.")); 901 } 902 903 errors ++; 904 } 905 906 if (ppd->product != NULL) 907 { 908 if (ppd->product[0] != '(' || 909 ppd->product[strlen(ppd->product) - 1] != ')') 910 { 911 if (verbose >= 0) 912 { 913 if (!errors && !verbose) 914 _cupsLangPuts(stdout, _(" FAIL")); 915 916 _cupsLangPuts(stdout, 917 _(" **FAIL** Bad Product - not \"(string)\".\n" 918 " REF: Page 62, section 5.3.")); 919 } 920 921 errors ++; 922 } 923 else if (verbose > 0) 924 _cupsLangPuts(stdout, _(" PASS Product")); 925 } 926 else 927 { 928 if (verbose >= 0) 929 { 930 if (!errors && !verbose) 931 _cupsLangPuts(stdout, _(" FAIL")); 932 933 _cupsLangPuts(stdout, 934 _(" **FAIL** REQUIRED Product\n" 935 " REF: Page 62, section 5.3.")); 936 } 937 938 errors ++; 939 } 940 941 if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL && 942 attr->value != NULL) 943 { 944 char junkstr[255]; /* Temp string */ 945 int junkint; /* Temp integer */ 946 947 948 if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2) 949 { 950 if (verbose >= 0) 951 { 952 if (!errors && !verbose) 953 _cupsLangPuts(stdout, _(" FAIL")); 954 955 _cupsLangPuts(stdout, 956 _(" **FAIL** Bad PSVersion - not \"(string) " 957 "int\".\n" 958 " REF: Pages 62-64, section 5.3.")); 959 } 960 961 errors ++; 962 } 963 else if (verbose > 0) 964 _cupsLangPuts(stdout, _(" PASS PSVersion")); 965 } 966 else 967 { 968 if (verbose >= 0) 969 { 970 if (!errors && !verbose) 971 _cupsLangPuts(stdout, _(" FAIL")); 972 973 _cupsLangPuts(stdout, 974 _(" **FAIL** REQUIRED PSVersion\n" 975 " REF: Pages 62-64, section 5.3.")); 976 } 977 978 errors ++; 979 } 980 981 if (ppd->shortnickname != NULL) 982 { 983 if (strlen(ppd->shortnickname) > 31) 984 { 985 if (verbose >= 0) 986 { 987 if (!errors && !verbose) 988 _cupsLangPuts(stdout, _(" FAIL")); 989 990 _cupsLangPuts(stdout, 991 _(" **FAIL** Bad ShortNickName - longer " 992 "than 31 chars.\n" 993 " REF: Pages 64-65, section 5.3.")); 994 } 995 996 errors ++; 997 } 998 else if (verbose > 0) 999 _cupsLangPuts(stdout, _(" PASS ShortNickName")); 1000 } 1001 else if (ppdversion >= 43) 1002 { 1003 if (verbose >= 0) 1004 { 1005 if (!errors && !verbose) 1006 _cupsLangPuts(stdout, _(" FAIL")); 1007 1008 _cupsLangPuts(stdout, 1009 _(" **FAIL** REQUIRED ShortNickName\n" 1010 " REF: Page 64-65, section 5.3.")); 1011 } 1012 1013 errors ++; 1014 } 1015 1016 if (ppd->patches != NULL && strchr(ppd->patches, '\"') && 1017 strstr(ppd->patches, "*End")) 1018 { 1019 if (verbose >= 0) 1020 { 1021 if (!errors && !verbose) 1022 _cupsLangPuts(stdout, _(" FAIL")); 1023 1024 _cupsLangPuts(stdout, 1025 _(" **FAIL** Bad JobPatchFile attribute in file\n" 1026 " REF: Page 24, section 3.4.")); 1027 } 1028 1029 errors ++; 1030 } 1031 1032 /* 1033 * Check for page sizes without the corresponding ImageableArea or 1034 * PaperDimension values... 1035 */ 1036 1037 if (ppd->num_sizes == 0) 1038 { 1039 if (verbose >= 0) 1040 { 1041 if (!errors && !verbose) 1042 _cupsLangPuts(stdout, _(" FAIL")); 1043 1044 _cupsLangPuts(stdout, 1045 _(" **FAIL** REQUIRED PageSize\n" 1046 " REF: Page 41, section 5.\n" 1047 " REF: Page 99, section 5.14.")); 1048 } 1049 1050 errors ++; 1051 } 1052 else 1053 { 1054 for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++) 1055 { 1056 /* 1057 * Don't check custom size... 1058 */ 1059 1060 if (!strcmp(size->name, "Custom")) 1061 continue; 1062 1063 /* 1064 * Check for ImageableArea... 1065 */ 1066 1067 if (size->left == 0.0 && size->bottom == 0.0 && 1068 size->right == 0.0 && size->top == 0.0) 1069 { 1070 if (verbose >= 0) 1071 { 1072 if (!errors && !verbose) 1073 _cupsLangPuts(stdout, _(" FAIL")); 1074 1075 _cupsLangPrintf(stdout, 1076 _(" **FAIL** REQUIRED ImageableArea for " 1077 "PageSize %s\n" 1078 " REF: Page 41, section 5.\n" 1079 " REF: Page 102, section 5.15."), 1080 size->name); 1081 } 1082 1083 errors ++; 1084 } 1085 1086 /* 1087 * Check for PaperDimension... 1088 */ 1089 1090 if (size->width <= 0.0 && size->length <= 0.0) 1091 { 1092 if (verbose >= 0) 1093 { 1094 if (!errors && !verbose) 1095 _cupsLangPuts(stdout, _(" FAIL")); 1096 1097 _cupsLangPrintf(stdout, 1098 _(" **FAIL** REQUIRED PaperDimension " 1099 "for PageSize %s\n" 1100 " REF: Page 41, section 5.\n" 1101 " REF: Page 103, section 5.15."), 1102 size->name); 1103 } 1104 1105 errors ++; 1106 } 1107 } 1108 } 1109 1110 /* 1111 * Check for valid Resolution, JCLResolution, or SetResolution values... 1112 */ 1113 1114 if ((option = ppdFindOption(ppd, "Resolution")) == NULL) 1115 if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL) 1116 option = ppdFindOption(ppd, "SetResolution"); 1117 1118 if (option != NULL) 1119 { 1120 for (j = option->num_choices, choice = option->choices; 1121 j > 0; 1122 j --, choice ++) 1123 { 1124 /* 1125 * Verify that all resolution options are of the form NNNdpi 1126 * or NNNxNNNdpi... 1127 */ 1128 1129 xdpi = strtol(choice->choice, (char **)&ptr, 10); 1130 if (ptr > choice->choice && xdpi > 0) 1131 { 1132 if (*ptr == 'x') 1133 ydpi = strtol(ptr + 1, (char **)&ptr, 10); 1134 else 1135 ydpi = xdpi; 1136 } 1137 else 1138 ydpi = xdpi; 1139 1140 if (xdpi <= 0 || xdpi > 99999 || ydpi <= 0 || ydpi > 99999 || 1141 strcmp(ptr, "dpi")) 1142 { 1143 if (verbose >= 0) 1144 { 1145 if (!errors && !verbose) 1146 _cupsLangPuts(stdout, _(" FAIL")); 1147 1148 _cupsLangPrintf(stdout, 1149 _(" **FAIL** Bad option %s choice %s\n" 1150 " REF: Page 84, section 5.9"), 1151 option->keyword, choice->choice); 1152 } 1153 1154 errors ++; 1155 } 1156 } 1157 } 1158 1159 if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) && 1160 strcmp(attr->name, "1284DeviceID")) 1161 { 1162 if (verbose >= 0) 1163 { 1164 if (!errors && !verbose) 1165 _cupsLangPuts(stdout, _(" FAIL")); 1166 1167 _cupsLangPrintf(stdout, 1168 _(" **FAIL** %s must be 1284DeviceID\n" 1169 " REF: Page 72, section 5.5"), 1170 attr->name); 1171 } 1172 1173 errors ++; 1174 } 1175 1176 errors = check_case(ppd, errors, verbose); 1177 1178 if (!(warn & WARN_CONSTRAINTS)) 1179 errors = check_constraints(ppd, errors, verbose, 0); 1180 1181 if (!(warn & WARN_FILTERS) && !(ignore & WARN_FILTERS)) 1182 errors = check_filters(ppd, root, errors, verbose, 0); 1183 1184 if (!(warn & WARN_PROFILES) && !(ignore & WARN_PROFILES)) 1185 errors = check_profiles(ppd, root, errors, verbose, 0); 1186 1187 if (!(warn & WARN_SIZES)) 1188 errors = check_sizes(ppd, errors, verbose, 0); 1189 1190 if (!(warn & WARN_TRANSLATIONS)) 1191 errors = check_translations(ppd, errors, verbose, 0); 1192 1193 if (!(warn & WARN_DUPLEX)) 1194 errors = check_duplex(ppd, errors, verbose, 0); 1195 1196 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL && 1197 attr->value) 1198 { 1199 /* 1200 * This file contains localizations, check for conformance of the 1201 * base translation... 1202 */ 1203 1204 if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL) 1205 { 1206 if (!attr->value || strcmp(attr->value, "ISOLatin1")) 1207 { 1208 if (!errors && !verbose) 1209 _cupsLangPuts(stdout, _(" FAIL")); 1210 1211 if (verbose >= 0) 1212 _cupsLangPrintf(stdout, 1213 _(" **FAIL** Bad LanguageEncoding %s - " 1214 "must be ISOLatin1."), 1215 attr->value ? attr->value : "(null)"); 1216 1217 errors ++; 1218 } 1219 1220 if (!ppd->lang_version || strcmp(ppd->lang_version, "English")) 1221 { 1222 if (!errors && !verbose) 1223 _cupsLangPuts(stdout, _(" FAIL")); 1224 1225 if (verbose >= 0) 1226 _cupsLangPrintf(stdout, 1227 _(" **FAIL** Bad LanguageVersion %s - " 1228 "must be English."), 1229 ppd->lang_version ? ppd->lang_version : "(null)"); 1230 1231 errors ++; 1232 } 1233 1234 /* 1235 * Loop through all options and choices... 1236 */ 1237 1238 for (option = ppdFirstOption(ppd); 1239 option; 1240 option = ppdNextOption(ppd)) 1241 { 1242 /* 1243 * Check for special characters outside A0 to BF, F7, or F8 1244 * that are used for languages other than English. 1245 */ 1246 1247 for (ptr = option->text; *ptr; ptr ++) 1248 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 && 1249 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8) 1250 break; 1251 1252 if (*ptr) 1253 { 1254 if (!errors && !verbose) 1255 _cupsLangPuts(stdout, _(" FAIL")); 1256 1257 if (verbose >= 0) 1258 _cupsLangPrintf(stdout, 1259 _(" **FAIL** Default translation " 1260 "string for option %s contains 8-bit " 1261 "characters."), 1262 option->keyword); 1263 1264 errors ++; 1265 } 1266 1267 for (j = 0; j < option->num_choices; j ++) 1268 { 1269 /* 1270 * Check for special characters outside A0 to BF, F7, or F8 1271 * that are used for languages other than English. 1272 */ 1273 1274 for (ptr = option->choices[j].text; *ptr; ptr ++) 1275 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 && 1276 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8) 1277 break; 1278 1279 if (*ptr) 1280 { 1281 if (!errors && !verbose) 1282 _cupsLangPuts(stdout, _(" FAIL")); 1283 1284 if (verbose >= 0) 1285 _cupsLangPrintf(stdout, 1286 _(" **FAIL** Default translation " 1287 "string for option %s choice %s contains " 1288 "8-bit characters."), 1289 option->keyword, 1290 option->choices[j].choice); 1291 1292 errors ++; 1293 } 1294 } 1295 } 1296 } 1297 } 1298 1299 /* 1300 * Final pass/fail notification... 1301 */ 1302 1303 if (errors) 1304 status = ERROR_CONFORMANCE; 1305 else if (!verbose) 1306 _cupsLangPuts(stdout, _(" PASS")); 1307 1308 if (verbose >= 0) 1309 { 1310 check_basics(argv[i]); 1311 1312 if (warn & WARN_DEFAULTS) 1313 errors = check_defaults(ppd, errors, verbose, 1); 1314 1315 if (warn & WARN_CONSTRAINTS) 1316 errors = check_constraints(ppd, errors, verbose, 1); 1317 1318 if ((warn & WARN_FILTERS) && !(ignore & WARN_FILTERS)) 1319 errors = check_filters(ppd, root, errors, verbose, 1); 1320 1321 if ((warn & WARN_PROFILES) && !(ignore & WARN_PROFILES)) 1322 errors = check_profiles(ppd, root, errors, verbose, 1); 1323 1324 if (warn & WARN_SIZES) 1325 errors = check_sizes(ppd, errors, verbose, 1); 1326 else 1327 errors = check_sizes(ppd, errors, verbose, 2); 1328 1329 if (warn & WARN_TRANSLATIONS) 1330 errors = check_translations(ppd, errors, verbose, 1); 1331 1332 if (warn & WARN_DUPLEX) 1333 errors = check_duplex(ppd, errors, verbose, 1); 1334 1335 /* 1336 * Look for legacy duplex keywords... 1337 */ 1338 1339 if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL) 1340 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL) 1341 option = ppdFindOption(ppd, "KD03Duplex"); 1342 1343 if (option) 1344 _cupsLangPrintf(stdout, 1345 _(" WARN Duplex option keyword %s may not " 1346 "work as expected and should be named Duplex.\n" 1347 " REF: Page 122, section 5.17"), 1348 option->keyword); 1349 1350 /* 1351 * Look for default keywords with no corresponding option... 1352 */ 1353 1354 for (j = 0; j < ppd->num_attrs; j ++) 1355 { 1356 attr = ppd->attrs[j]; 1357 1358 if (!strcmp(attr->name, "DefaultColorSpace") || 1359 !strcmp(attr->name, "DefaultColorSep") || 1360 !strcmp(attr->name, "DefaultFont") || 1361 !strcmp(attr->name, "DefaultHalftoneType") || 1362 !strcmp(attr->name, "DefaultImageableArea") || 1363 !strcmp(attr->name, "DefaultLeadingEdge") || 1364 !strcmp(attr->name, "DefaultOutputOrder") || 1365 !strcmp(attr->name, "DefaultPaperDimension") || 1366 !strcmp(attr->name, "DefaultResolution") || 1367 !strcmp(attr->name, "DefaultScreenProc") || 1368 !strcmp(attr->name, "DefaultTransfer")) 1369 continue; 1370 1371 if (!strncmp(attr->name, "Default", 7) && 1372 !ppdFindOption(ppd, attr->name + 7)) 1373 _cupsLangPrintf(stdout, 1374 _(" WARN %s has no corresponding " 1375 "options."), 1376 attr->name); 1377 } 1378 1379 if (ppdversion < 43) 1380 { 1381 _cupsLangPrintf(stdout, 1382 _(" WARN Obsolete PPD version %.1f.\n" 1383 " REF: Page 42, section 5.2."), 1384 0.1f * ppdversion); 1385 } 1386 1387 if (!ppd->lang_encoding && ppdversion < 41) 1388 { 1389 _cupsLangPuts(stdout, 1390 _(" WARN LanguageEncoding required by PPD " 1391 "4.3 spec.\n" 1392 " REF: Pages 56-57, section 5.3.")); 1393 } 1394 1395 if (!ppd->manufacturer && ppdversion < 43) 1396 { 1397 _cupsLangPuts(stdout, 1398 _(" WARN Manufacturer required by PPD " 1399 "4.3 spec.\n" 1400 " REF: Pages 58-59, section 5.3.")); 1401 } 1402 1403 /* 1404 * Treat a PCFileName attribute longer than 12 characters as 1405 * a warning and not a hard error... 1406 */ 1407 1408 if (!(ignore & WARN_FILENAME) && ppd->pcfilename) 1409 { 1410 if (strlen(ppd->pcfilename) > 12) 1411 { 1412 _cupsLangPuts(stdout, 1413 _(" WARN PCFileName longer than 8.3 in " 1414 "violation of PPD spec.\n" 1415 " REF: Pages 61-62, section " 1416 "5.3.")); 1417 } 1418 1419 if (!_cups_strcasecmp(ppd->pcfilename, "unused.ppd")) 1420 _cupsLangPuts(stdout, 1421 _(" WARN PCFileName should contain a " 1422 "unique filename.\n" 1423 " REF: Pages 61-62, section " 1424 "5.3.")); 1425 } 1426 1427 if (!ppd->shortnickname && ppdversion < 43) 1428 { 1429 _cupsLangPuts(stdout, 1430 _(" WARN ShortNickName required by PPD " 1431 "4.3 spec.\n" 1432 " REF: Pages 64-65, section 5.3.")); 1433 } 1434 1435 /* 1436 * Check the Protocols line and flag PJL + BCP since TBCP is 1437 * usually used with PJL... 1438 */ 1439 1440 if (ppd->protocols) 1441 { 1442 if (strstr(ppd->protocols, "PJL") && 1443 strstr(ppd->protocols, "BCP") && 1444 !strstr(ppd->protocols, "TBCP")) 1445 { 1446 _cupsLangPuts(stdout, 1447 _(" WARN Protocols contains both PJL " 1448 "and BCP; expected TBCP.\n" 1449 " REF: Pages 78-79, section 5.7.")); 1450 } 1451 1452 if (strstr(ppd->protocols, "PJL") && 1453 (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps)) 1454 { 1455 _cupsLangPuts(stdout, 1456 _(" WARN Protocols contains PJL but JCL " 1457 "attributes are not set.\n" 1458 " REF: Pages 78-79, section 5.7.")); 1459 } 1460 } 1461 1462 /* 1463 * Check for options with a common prefix, e.g. Duplex and Duplexer, 1464 * which are errors according to the spec but won't cause problems 1465 * with CUPS specifically... 1466 */ 1467 1468 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) 1469 for (k = 0, option = group->options; 1470 k < group->num_options; 1471 k ++, option ++) 1472 { 1473 len = strlen(option->keyword); 1474 1475 for (m = 0, group2 = ppd->groups; 1476 m < ppd->num_groups; 1477 m ++, group2 ++) 1478 for (n = 0, option2 = group2->options; 1479 n < group2->num_options; 1480 n ++, option2 ++) 1481 if (option != option2 && 1482 len < strlen(option2->keyword) && 1483 !strncmp(option->keyword, option2->keyword, len)) 1484 { 1485 _cupsLangPrintf(stdout, 1486 _(" WARN %s shares a common " 1487 "prefix with %s\n" 1488 " REF: Page 15, section " 1489 "3.2."), 1490 option->keyword, option2->keyword); 1491 } 1492 } 1493 } 1494 1495 if (verbose > 0) 1496 { 1497 if (errors) 1498 _cupsLangPrintf(stdout, _(" %d ERRORS FOUND"), errors); 1499 else 1500 _cupsLangPuts(stdout, _(" NO ERRORS FOUND")); 1501 } 1502 1503 /* 1504 * Then list the options, if "-v" was provided... 1505 */ 1506 1507 if (verbose > 1) 1508 { 1509 _cupsLangPrintf(stdout, 1510 "\n" 1511 " language_level = %d\n" 1512 " color_device = %s\n" 1513 " variable_sizes = %s\n" 1514 " landscape = %d", 1515 ppd->language_level, 1516 ppd->color_device ? "TRUE" : "FALSE", 1517 ppd->variable_sizes ? "TRUE" : "FALSE", 1518 ppd->landscape); 1519 1520 switch (ppd->colorspace) 1521 { 1522 case PPD_CS_CMYK : 1523 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMYK"); 1524 break; 1525 case PPD_CS_CMY : 1526 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMY"); 1527 break; 1528 case PPD_CS_GRAY : 1529 _cupsLangPuts(stdout, " colorspace = PPD_CS_GRAY"); 1530 break; 1531 case PPD_CS_RGB : 1532 _cupsLangPuts(stdout, " colorspace = PPD_CS_RGB"); 1533 break; 1534 default : 1535 _cupsLangPuts(stdout, " colorspace = <unknown>"); 1536 break; 1537 } 1538 1539 _cupsLangPrintf(stdout, " num_emulations = %d", 1540 ppd->num_emulations); 1541 for (j = 0; j < ppd->num_emulations; j ++) 1542 _cupsLangPrintf(stdout, " emulations[%d] = %s", 1543 j, ppd->emulations[j].name); 1544 1545 _cupsLangPrintf(stdout, " lang_encoding = %s", 1546 ppd->lang_encoding); 1547 _cupsLangPrintf(stdout, " lang_version = %s", 1548 ppd->lang_version); 1549 _cupsLangPrintf(stdout, " modelname = %s", ppd->modelname); 1550 _cupsLangPrintf(stdout, " ttrasterizer = %s", 1551 ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer); 1552 _cupsLangPrintf(stdout, " manufacturer = %s", 1553 ppd->manufacturer); 1554 _cupsLangPrintf(stdout, " product = %s", ppd->product); 1555 _cupsLangPrintf(stdout, " nickname = %s", ppd->nickname); 1556 _cupsLangPrintf(stdout, " shortnickname = %s", 1557 ppd->shortnickname); 1558 _cupsLangPrintf(stdout, " patches = %d bytes", 1559 ppd->patches == NULL ? 0 : (int)strlen(ppd->patches)); 1560 1561 _cupsLangPrintf(stdout, " num_groups = %d", ppd->num_groups); 1562 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) 1563 { 1564 _cupsLangPrintf(stdout, " group[%d] = %s", 1565 j, group->text); 1566 1567 for (k = 0, option = group->options; k < group->num_options; k ++, option ++) 1568 { 1569 _cupsLangPrintf(stdout, 1570 " options[%d] = %s (%s) %s %s %.0f " 1571 "(%d choices)", 1572 k, option->keyword, option->text, uis[option->ui], 1573 sections[option->section], option->order, 1574 option->num_choices); 1575 1576 if (!strcmp(option->keyword, "PageSize") || 1577 !strcmp(option->keyword, "PageRegion")) 1578 { 1579 for (m = option->num_choices, choice = option->choices; 1580 m > 0; 1581 m --, choice ++) 1582 { 1583 size = ppdPageSize(ppd, choice->choice); 1584 1585 if (size == NULL) 1586 _cupsLangPrintf(stdout, 1587 " %s (%s) = ERROR%s", 1588 choice->choice, choice->text, 1589 !strcmp(option->defchoice, choice->choice) 1590 ? " *" : ""); 1591 else 1592 _cupsLangPrintf(stdout, 1593 " %s (%s) = %.2fx%.2fin " 1594 "(%.1f,%.1f,%.1f,%.1f)%s", 1595 choice->choice, choice->text, 1596 size->width / 72.0, size->length / 72.0, 1597 size->left / 72.0, size->bottom / 72.0, 1598 size->right / 72.0, size->top / 72.0, 1599 !strcmp(option->defchoice, choice->choice) 1600 ? " *" : ""); 1601 } 1602 } 1603 else 1604 { 1605 for (m = option->num_choices, choice = option->choices; 1606 m > 0; 1607 m --, choice ++) 1608 { 1609 _cupsLangPrintf(stdout, " %s (%s)%s", 1610 choice->choice, choice->text, 1611 !strcmp(option->defchoice, choice->choice) 1612 ? " *" : ""); 1613 } 1614 } 1615 } 1616 } 1617 1618 _cupsLangPrintf(stdout, " num_consts = %d", 1619 ppd->num_consts); 1620 for (j = 0; j < ppd->num_consts; j ++) 1621 _cupsLangPrintf(stdout, 1622 " consts[%d] = *%s %s *%s %s", 1623 j, ppd->consts[j].option1, ppd->consts[j].choice1, 1624 ppd->consts[j].option2, ppd->consts[j].choice2); 1625 1626 _cupsLangPrintf(stdout, " num_profiles = %d", 1627 ppd->num_profiles); 1628 for (j = 0; j < ppd->num_profiles; j ++) 1629 _cupsLangPrintf(stdout, 1630 " profiles[%d] = %s/%s %.3f %.3f " 1631 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]", 1632 j, ppd->profiles[j].resolution, 1633 ppd->profiles[j].media_type, 1634 ppd->profiles[j].gamma, ppd->profiles[j].density, 1635 ppd->profiles[j].matrix[0][0], 1636 ppd->profiles[j].matrix[0][1], 1637 ppd->profiles[j].matrix[0][2], 1638 ppd->profiles[j].matrix[1][0], 1639 ppd->profiles[j].matrix[1][1], 1640 ppd->profiles[j].matrix[1][2], 1641 ppd->profiles[j].matrix[2][0], 1642 ppd->profiles[j].matrix[2][1], 1643 ppd->profiles[j].matrix[2][2]); 1644 1645 _cupsLangPrintf(stdout, " num_fonts = %d", ppd->num_fonts); 1646 for (j = 0; j < ppd->num_fonts; j ++) 1647 _cupsLangPrintf(stdout, " fonts[%d] = %s", 1648 j, ppd->fonts[j]); 1649 1650 _cupsLangPrintf(stdout, " num_attrs = %d", ppd->num_attrs); 1651 for (j = 0; j < ppd->num_attrs; j ++) 1652 _cupsLangPrintf(stdout, 1653 " attrs[%d] = %s %s%s%s: \"%s\"", j, 1654 ppd->attrs[j]->name, ppd->attrs[j]->spec, 1655 ppd->attrs[j]->text[0] ? "/" : "", 1656 ppd->attrs[j]->text, 1657 ppd->attrs[j]->value ? 1658 ppd->attrs[j]->value : "(null)"); 1659 } 1660 1661 ppdClose(ppd); 1662 } 1663 1664 if (!files) 1665 usage(); 1666 1667 return (status); 1668} 1669 1670 1671/* 1672 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines. 1673 */ 1674 1675static void 1676check_basics(const char *filename) /* I - PPD file to check */ 1677{ 1678 cups_file_t *fp; /* File pointer */ 1679 int ch; /* Current character */ 1680 int col, /* Current column */ 1681 whitespace; /* Only seen whitespace? */ 1682 int eol; /* Line endings */ 1683 int linenum; /* Line number */ 1684 int mixed; /* Mixed line endings? */ 1685 1686 1687 if ((fp = cupsFileOpen(filename, "r")) == NULL) 1688 return; 1689 1690 linenum = 1; 1691 col = 0; 1692 eol = EOL_NONE; 1693 mixed = 0; 1694 whitespace = 1; 1695 1696 while ((ch = cupsFileGetChar(fp)) != EOF) 1697 { 1698 if (ch == '\r' || ch == '\n') 1699 { 1700 if (ch == '\n') 1701 { 1702 if (eol == EOL_NONE) 1703 eol = EOL_LF; 1704 else if (eol != EOL_LF) 1705 mixed = 1; 1706 } 1707 else if (ch == '\r') 1708 { 1709 if (cupsFilePeekChar(fp) == '\n') 1710 { 1711 cupsFileGetChar(fp); 1712 1713 if (eol == EOL_NONE) 1714 eol = EOL_CRLF; 1715 else if (eol != EOL_CRLF) 1716 mixed = 1; 1717 } 1718 else if (eol == EOL_NONE) 1719 eol = EOL_CR; 1720 else if (eol != EOL_CR) 1721 mixed = 1; 1722 } 1723 1724 if (col > 0 && whitespace) 1725 _cupsLangPrintf(stdout, 1726 _(" WARN Line %d only contains whitespace."), 1727 linenum); 1728 1729 linenum ++; 1730 col = 0; 1731 whitespace = 1; 1732 } 1733 else 1734 { 1735 if (ch != ' ' && ch != '\t') 1736 whitespace = 0; 1737 1738 col ++; 1739 } 1740 } 1741 1742 if (mixed) 1743 _cupsLangPuts(stdout, 1744 _(" WARN File contains a mix of CR, LF, and " 1745 "CR LF line endings.")); 1746 1747 if (eol == EOL_CRLF) 1748 _cupsLangPuts(stdout, 1749 _(" WARN Non-Windows PPD files should use lines " 1750 "ending with only LF, not CR LF.")); 1751 1752 cupsFileClose(fp); 1753} 1754 1755 1756/* 1757 * 'check_constraints()' - Check UIConstraints in the PPD file. 1758 */ 1759 1760static int /* O - Errors found */ 1761check_constraints(ppd_file_t *ppd, /* I - PPD file */ 1762 int errors, /* I - Errors found */ 1763 int verbose, /* I - Verbosity level */ 1764 int warn) /* I - Warnings only? */ 1765{ 1766 int i; /* Looping var */ 1767 const char *prefix; /* WARN/FAIL prefix */ 1768 ppd_const_t *c; /* Current UIConstraints data */ 1769 ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */ 1770 const char *vptr; /* Pointer into constraint value */ 1771 char option[PPD_MAX_NAME], 1772 /* Option name/MainKeyword */ 1773 choice[PPD_MAX_NAME], 1774 /* Choice/OptionKeyword */ 1775 *ptr; /* Pointer into option or choice */ 1776 int num_options; /* Number of options */ 1777 cups_option_t *options; /* Options */ 1778 ppd_option_t *o; /* PPD option */ 1779 1780 1781 prefix = warn ? " WARN " : "**FAIL**"; 1782 1783 1784 /* 1785 * See what kind of constraint data we have in the PPD... 1786 */ 1787 1788 if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL) 1789 { 1790 /* 1791 * Check new-style cupsUIConstraints data... 1792 */ 1793 1794 for (; constattr; 1795 constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL)) 1796 { 1797 if (!constattr->value) 1798 { 1799 if (!warn && !errors && !verbose) 1800 _cupsLangPuts(stdout, _(" FAIL")); 1801 1802 _cupsLangPrintf(stdout, 1803 _(" %s Empty cupsUIConstraints %s"), 1804 prefix, constattr->spec); 1805 1806 if (!warn) 1807 errors ++; 1808 1809 continue; 1810 } 1811 1812 for (i = 0, vptr = strchr(constattr->value, '*'); 1813 vptr; 1814 i ++, vptr = strchr(vptr + 1, '*')); 1815 1816 if (i == 0) 1817 { 1818 if (!warn && !errors && !verbose) 1819 _cupsLangPuts(stdout, _(" FAIL")); 1820 1821 _cupsLangPrintf(stdout, 1822 _(" %s Bad cupsUIConstraints %s: \"%s\""), 1823 prefix, constattr->spec, constattr->value); 1824 1825 if (!warn) 1826 errors ++; 1827 1828 continue; 1829 } 1830 1831 cupsArraySave(ppd->sorted_attrs); 1832 1833 if (constattr->spec[0] && 1834 !ppdFindAttr(ppd, "cupsUIResolver", constattr->spec)) 1835 { 1836 if (!warn && !errors && !verbose) 1837 _cupsLangPuts(stdout, _(" FAIL")); 1838 1839 _cupsLangPrintf(stdout, 1840 _(" %s Missing cupsUIResolver %s"), 1841 prefix, constattr->spec); 1842 1843 if (!warn) 1844 errors ++; 1845 } 1846 1847 cupsArrayRestore(ppd->sorted_attrs); 1848 1849 num_options = 0; 1850 options = NULL; 1851 1852 for (vptr = strchr(constattr->value, '*'); 1853 vptr; 1854 vptr = strchr(vptr, '*')) 1855 { 1856 /* 1857 * Extract "*Option Choice" or just "*Option"... 1858 */ 1859 1860 for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++) 1861 if (ptr < (option + sizeof(option) - 1)) 1862 *ptr++ = *vptr; 1863 1864 *ptr = '\0'; 1865 1866 while (isspace(*vptr & 255)) 1867 vptr ++; 1868 1869 if (*vptr == '*') 1870 choice[0] = '\0'; 1871 else 1872 { 1873 for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++) 1874 if (ptr < (choice + sizeof(choice) - 1)) 1875 *ptr++ = *vptr; 1876 1877 *ptr = '\0'; 1878 } 1879 1880 if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True")) 1881 { 1882 _cups_strcpy(option, option + 6); 1883 strlcpy(choice, "Custom", sizeof(choice)); 1884 } 1885 1886 if ((o = ppdFindOption(ppd, option)) == NULL) 1887 { 1888 if (!warn && !errors && !verbose) 1889 _cupsLangPuts(stdout, _(" FAIL")); 1890 1891 _cupsLangPrintf(stdout, 1892 _(" %s Missing option %s in " 1893 "cupsUIConstraints %s: \"%s\""), 1894 prefix, option, constattr->spec, constattr->value); 1895 1896 if (!warn) 1897 errors ++; 1898 1899 continue; 1900 } 1901 1902 if (choice[0] && !ppdFindChoice(o, choice)) 1903 { 1904 if (!warn && !errors && !verbose) 1905 _cupsLangPuts(stdout, _(" FAIL")); 1906 1907 _cupsLangPrintf(stdout, 1908 _(" %s Missing choice *%s %s in " 1909 "cupsUIConstraints %s: \"%s\""), 1910 prefix, option, choice, constattr->spec, 1911 constattr->value); 1912 1913 if (!warn) 1914 errors ++; 1915 1916 continue; 1917 } 1918 1919 if (choice[0]) 1920 num_options = cupsAddOption(option, choice, num_options, &options); 1921 else 1922 { 1923 for (i = 0; i < o->num_choices; i ++) 1924 if (_cups_strcasecmp(o->choices[i].choice, "None") && 1925 _cups_strcasecmp(o->choices[i].choice, "Off") && 1926 _cups_strcasecmp(o->choices[i].choice, "False")) 1927 { 1928 num_options = cupsAddOption(option, o->choices[i].choice, 1929 num_options, &options); 1930 break; 1931 } 1932 } 1933 } 1934 1935 /* 1936 * Resolvers must list at least two options... 1937 */ 1938 1939 if (num_options < 2) 1940 { 1941 if (!warn && !errors && !verbose) 1942 _cupsLangPuts(stdout, _(" FAIL")); 1943 1944 _cupsLangPrintf(stdout, 1945 _(" %s cupsUIResolver %s does not list at least " 1946 "two different options."), 1947 prefix, constattr->spec); 1948 1949 if (!warn) 1950 errors ++; 1951 } 1952 1953 /* 1954 * Test the resolver... 1955 */ 1956 1957 if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options)) 1958 { 1959 if (!warn && !errors && !verbose) 1960 _cupsLangPuts(stdout, _(" FAIL")); 1961 1962 _cupsLangPrintf(stdout, 1963 _(" %s cupsUIResolver %s causes a loop."), 1964 prefix, constattr->spec); 1965 1966 if (!warn) 1967 errors ++; 1968 } 1969 1970 cupsFreeOptions(num_options, options); 1971 } 1972 } 1973 else 1974 { 1975 /* 1976 * Check old-style [Non]UIConstraints data... 1977 */ 1978 1979 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++) 1980 { 1981 if (!_cups_strncasecmp(c->option1, "Custom", 6) && 1982 !_cups_strcasecmp(c->choice1, "True")) 1983 { 1984 strlcpy(option, c->option1 + 6, sizeof(option)); 1985 strlcpy(choice, "Custom", sizeof(choice)); 1986 } 1987 else 1988 { 1989 strlcpy(option, c->option1, sizeof(option)); 1990 strlcpy(choice, c->choice1, sizeof(choice)); 1991 } 1992 1993 if ((o = ppdFindOption(ppd, option)) == NULL) 1994 { 1995 if (!warn && !errors && !verbose) 1996 _cupsLangPuts(stdout, _(" FAIL")); 1997 1998 _cupsLangPrintf(stdout, 1999 _(" %s Missing option %s in " 2000 "UIConstraints \"*%s %s *%s %s\"."), 2001 prefix, c->option1, 2002 c->option1, c->choice1, c->option2, c->choice2); 2003 2004 if (!warn) 2005 errors ++; 2006 } 2007 else if (choice[0] && !ppdFindChoice(o, choice)) 2008 { 2009 if (!warn && !errors && !verbose) 2010 _cupsLangPuts(stdout, _(" FAIL")); 2011 2012 _cupsLangPrintf(stdout, 2013 _(" %s Missing choice *%s %s in " 2014 "UIConstraints \"*%s %s *%s %s\"."), 2015 prefix, c->option1, c->choice1, 2016 c->option1, c->choice1, c->option2, c->choice2); 2017 2018 if (!warn) 2019 errors ++; 2020 } 2021 2022 if (!_cups_strncasecmp(c->option2, "Custom", 6) && 2023 !_cups_strcasecmp(c->choice2, "True")) 2024 { 2025 strlcpy(option, c->option2 + 6, sizeof(option)); 2026 strlcpy(choice, "Custom", sizeof(choice)); 2027 } 2028 else 2029 { 2030 strlcpy(option, c->option2, sizeof(option)); 2031 strlcpy(choice, c->choice2, sizeof(choice)); 2032 } 2033 2034 if ((o = ppdFindOption(ppd, option)) == NULL) 2035 { 2036 if (!warn && !errors && !verbose) 2037 _cupsLangPuts(stdout, _(" FAIL")); 2038 2039 _cupsLangPrintf(stdout, 2040 _(" %s Missing option %s in " 2041 "UIConstraints \"*%s %s *%s %s\"."), 2042 prefix, c->option2, 2043 c->option1, c->choice1, c->option2, c->choice2); 2044 2045 if (!warn) 2046 errors ++; 2047 } 2048 else if (choice[0] && !ppdFindChoice(o, choice)) 2049 { 2050 if (!warn && !errors && !verbose) 2051 _cupsLangPuts(stdout, _(" FAIL")); 2052 2053 _cupsLangPrintf(stdout, 2054 _(" %s Missing choice *%s %s in " 2055 "UIConstraints \"*%s %s *%s %s\"."), 2056 prefix, c->option2, c->choice2, 2057 c->option1, c->choice1, c->option2, c->choice2); 2058 2059 if (!warn) 2060 errors ++; 2061 } 2062 } 2063 } 2064 2065 return (errors); 2066} 2067 2068 2069/* 2070 * 'check_case()' - Check that there are no duplicate groups, options, 2071 * or choices that differ only by case. 2072 */ 2073 2074static int /* O - Errors found */ 2075check_case(ppd_file_t *ppd, /* I - PPD file */ 2076 int errors, /* I - Errors found */ 2077 int verbose) /* I - Verbosity level */ 2078{ 2079 int i, j; /* Looping vars */ 2080 ppd_group_t *groupa, /* First group */ 2081 *groupb; /* Second group */ 2082 ppd_option_t *optiona, /* First option */ 2083 *optionb; /* Second option */ 2084 ppd_choice_t *choicea, /* First choice */ 2085 *choiceb; /* Second choice */ 2086 2087 2088 /* 2089 * Check that the groups do not have any duplicate names... 2090 */ 2091 2092 for (i = ppd->num_groups, groupa = ppd->groups; i > 1; i --, groupa ++) 2093 for (j = i - 1, groupb = groupa + 1; j > 0; j --, groupb ++) 2094 if (!_cups_strcasecmp(groupa->name, groupb->name)) 2095 { 2096 if (!errors && !verbose) 2097 _cupsLangPuts(stdout, _(" FAIL")); 2098 2099 if (verbose >= 0) 2100 _cupsLangPrintf(stdout, 2101 _(" **FAIL** Group names %s and %s differ only " 2102 "by case."), 2103 groupa->name, groupb->name); 2104 2105 errors ++; 2106 } 2107 2108 /* 2109 * Check that the options do not have any duplicate names... 2110 */ 2111 2112 for (optiona = ppdFirstOption(ppd); optiona; optiona = ppdNextOption(ppd)) 2113 { 2114 cupsArraySave(ppd->options); 2115 for (optionb = ppdNextOption(ppd); optionb; optionb = ppdNextOption(ppd)) 2116 if (!_cups_strcasecmp(optiona->keyword, optionb->keyword)) 2117 { 2118 if (!errors && !verbose) 2119 _cupsLangPuts(stdout, _(" FAIL")); 2120 2121 if (verbose >= 0) 2122 _cupsLangPrintf(stdout, 2123 _(" **FAIL** Option names %s and %s differ only " 2124 "by case."), 2125 optiona->keyword, optionb->keyword); 2126 2127 errors ++; 2128 } 2129 cupsArrayRestore(ppd->options); 2130 2131 /* 2132 * Then the choices... 2133 */ 2134 2135 for (i = optiona->num_choices, choicea = optiona->choices; 2136 i > 1; 2137 i --, choicea ++) 2138 for (j = i - 1, choiceb = choicea + 1; j > 0; j --, choiceb ++) 2139 if (!strcmp(choicea->choice, choiceb->choice)) 2140 { 2141 if (!errors && !verbose) 2142 _cupsLangPuts(stdout, _(" FAIL")); 2143 2144 if (verbose >= 0) 2145 _cupsLangPrintf(stdout, 2146 _(" **FAIL** Multiple occurrences of " 2147 "option %s choice name %s."), 2148 optiona->keyword, choicea->choice); 2149 2150 errors ++; 2151 2152 choicea ++; 2153 i --; 2154 break; 2155 } 2156 else if (!_cups_strcasecmp(choicea->choice, choiceb->choice)) 2157 { 2158 if (!errors && !verbose) 2159 _cupsLangPuts(stdout, _(" FAIL")); 2160 2161 if (verbose >= 0) 2162 _cupsLangPrintf(stdout, 2163 _(" **FAIL** Option %s choice names %s and " 2164 "%s differ only by case."), 2165 optiona->keyword, choicea->choice, choiceb->choice); 2166 2167 errors ++; 2168 } 2169 } 2170 2171 /* 2172 * Return the number of errors found... 2173 */ 2174 2175 return (errors); 2176} 2177 2178 2179/* 2180 * 'check_defaults()' - Check default option keywords in the PPD file. 2181 */ 2182 2183static int /* O - Errors found */ 2184check_defaults(ppd_file_t *ppd, /* I - PPD file */ 2185 int errors, /* I - Errors found */ 2186 int verbose, /* I - Verbosity level */ 2187 int warn) /* I - Warnings only? */ 2188{ 2189 int j, k; /* Looping vars */ 2190 ppd_attr_t *attr; /* PPD attribute */ 2191 ppd_option_t *option; /* Standard UI option */ 2192 const char *prefix; /* WARN/FAIL prefix */ 2193 2194 2195 prefix = warn ? " WARN " : "**FAIL**"; 2196 2197 ppdMarkDefaults(ppd); 2198 if (ppdConflicts(ppd)) 2199 { 2200 if (!warn && !errors && !verbose) 2201 _cupsLangPuts(stdout, _(" FAIL")); 2202 2203 if (verbose >= 0) 2204 _cupsLangPrintf(stdout, 2205 _(" %s Default choices conflicting."), prefix); 2206 2207 show_conflicts(ppd, prefix); 2208 2209 if (!warn) 2210 errors ++; 2211 } 2212 2213 for (j = 0; j < ppd->num_attrs; j ++) 2214 { 2215 attr = ppd->attrs[j]; 2216 2217 if (!strcmp(attr->name, "DefaultColorSpace") || 2218 !strcmp(attr->name, "DefaultFont") || 2219 !strcmp(attr->name, "DefaultHalftoneType") || 2220 !strcmp(attr->name, "DefaultImageableArea") || 2221 !strcmp(attr->name, "DefaultLeadingEdge") || 2222 !strcmp(attr->name, "DefaultOutputOrder") || 2223 !strcmp(attr->name, "DefaultPaperDimension") || 2224 !strcmp(attr->name, "DefaultResolution") || 2225 !strcmp(attr->name, "DefaultTransfer")) 2226 continue; 2227 2228 if (!strncmp(attr->name, "Default", 7)) 2229 { 2230 if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL && 2231 strcmp(attr->value, "Unknown")) 2232 { 2233 /* 2234 * Check that the default option value matches a choice... 2235 */ 2236 2237 for (k = 0; k < option->num_choices; k ++) 2238 if (!strcmp(option->choices[k].choice, attr->value)) 2239 break; 2240 2241 if (k >= option->num_choices) 2242 { 2243 if (!warn && !errors && !verbose) 2244 _cupsLangPuts(stdout, _(" FAIL")); 2245 2246 if (verbose >= 0) 2247 _cupsLangPrintf(stdout, 2248 _(" %s %s %s does not exist."), 2249 prefix, attr->name, attr->value); 2250 2251 if (!warn) 2252 errors ++; 2253 } 2254 } 2255 } 2256 } 2257 2258 return (errors); 2259} 2260 2261 2262/* 2263 * 'check_duplex()' - Check duplex keywords in the PPD file. 2264 */ 2265 2266static int /* O - Errors found */ 2267check_duplex(ppd_file_t *ppd, /* I - PPD file */ 2268 int errors, /* I - Error found */ 2269 int verbose, /* I - Verbosity level */ 2270 int warn) /* I - Warnings only? */ 2271{ 2272 int i; /* Looping var */ 2273 ppd_option_t *option; /* PPD option */ 2274 ppd_choice_t *choice; /* Current choice */ 2275 const char *prefix; /* Message prefix */ 2276 2277 2278 prefix = warn ? " WARN " : "**FAIL**"; 2279 2280 /* 2281 * Check for a duplex option, and for standard values... 2282 */ 2283 2284 if ((option = ppdFindOption(ppd, "Duplex")) != NULL) 2285 { 2286 if (!ppdFindChoice(option, "None")) 2287 { 2288 if (verbose >= 0) 2289 { 2290 if (!warn && !errors && !verbose) 2291 _cupsLangPuts(stdout, _(" FAIL")); 2292 2293 _cupsLangPrintf(stdout, 2294 _(" %s REQUIRED %s does not define " 2295 "choice None.\n" 2296 " REF: Page 122, section 5.17"), 2297 prefix, option->keyword); 2298 } 2299 2300 if (!warn) 2301 errors ++; 2302 } 2303 2304 for (i = option->num_choices, choice = option->choices; 2305 i > 0; 2306 i --, choice ++) 2307 if (strcmp(choice->choice, "None") && 2308 strcmp(choice->choice, "DuplexNoTumble") && 2309 strcmp(choice->choice, "DuplexTumble") && 2310 strcmp(choice->choice, "SimplexTumble")) 2311 { 2312 if (verbose >= 0) 2313 { 2314 if (!warn && !errors && !verbose) 2315 _cupsLangPuts(stdout, _(" FAIL")); 2316 2317 _cupsLangPrintf(stdout, 2318 _(" %s Bad %s choice %s.\n" 2319 " REF: Page 122, section 5.17"), 2320 prefix, option->keyword, choice->choice); 2321 } 2322 2323 if (!warn) 2324 errors ++; 2325 } 2326 } 2327 2328 return (errors); 2329} 2330 2331 2332/* 2333 * 'check_filters()' - Check filters in the PPD file. 2334 */ 2335 2336static int /* O - Errors found */ 2337check_filters(ppd_file_t *ppd, /* I - PPD file */ 2338 const char *root, /* I - Root directory */ 2339 int errors, /* I - Errors found */ 2340 int verbose, /* I - Verbosity level */ 2341 int warn) /* I - Warnings only? */ 2342{ 2343 ppd_attr_t *attr; /* PPD attribute */ 2344 const char *ptr; /* Pointer into string */ 2345 char super[16], /* Super-type for filter */ 2346 type[256], /* Type for filter */ 2347 dstsuper[16], /* Destination super-type for filter */ 2348 dsttype[256], /* Destination type for filter */ 2349 program[1024], /* Program/filter name */ 2350 pathprog[1024]; /* Complete path to program/filter */ 2351 int cost; /* Cost of filter */ 2352 const char *prefix; /* WARN/FAIL prefix */ 2353 struct stat fileinfo; /* File information */ 2354 2355 2356 prefix = warn ? " WARN " : "**FAIL**"; 2357 2358 /* 2359 * cupsFilter 2360 */ 2361 2362 for (attr = ppdFindAttr(ppd, "cupsFilter", NULL); 2363 attr; 2364 attr = ppdFindNextAttr(ppd, "cupsFilter", NULL)) 2365 { 2366 if (strcmp(attr->name, "cupsFilter")) 2367 { 2368 if (!warn && !errors && !verbose) 2369 _cupsLangPuts(stdout, _(" FAIL")); 2370 2371 if (verbose >= 0) 2372 _cupsLangPrintf(stdout, 2373 _(" %s Bad spelling of %s - should be %s."), 2374 prefix, attr->name, "cupsFilter"); 2375 2376 if (!warn) 2377 errors ++; 2378 } 2379 2380 if (!attr->value || 2381 sscanf(attr->value, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, 2382 &cost, program) != 4) 2383 { 2384 if (!warn && !errors && !verbose) 2385 _cupsLangPuts(stdout, _(" FAIL")); 2386 2387 if (verbose >= 0) 2388 _cupsLangPrintf(stdout, 2389 _(" %s Bad cupsFilter value \"%s\"."), 2390 prefix, attr->value); 2391 2392 if (!warn) 2393 errors ++; 2394 } 2395 else if (strcmp(program, "-")) 2396 { 2397 if (program[0] == '/') 2398 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program); 2399 else 2400 { 2401 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL) 2402 ptr = CUPS_SERVERBIN; 2403 2404 if (*ptr == '/' || !*root) 2405 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr, 2406 program); 2407 else 2408 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr, 2409 program); 2410 } 2411 2412 if (stat(pathprog, &fileinfo)) 2413 { 2414 if (!warn && !errors && !verbose) 2415 _cupsLangPuts(stdout, _(" FAIL")); 2416 2417 if (verbose >= 0) 2418 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2419 prefix, "cupsFilter", pathprog); 2420 2421 if (!warn) 2422 errors ++; 2423 } 2424 else if (fileinfo.st_uid != 0 || 2425 (fileinfo.st_mode & MODE_WRITE) || 2426 (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM) 2427 { 2428 if (!warn && !errors && !verbose) 2429 _cupsLangPuts(stdout, _(" FAIL")); 2430 2431 if (verbose >= 0) 2432 _cupsLangPrintf(stdout, 2433 _(" %s Bad permissions on %s file \"%s\"."), 2434 prefix, "cupsFilter", pathprog); 2435 2436 if (!warn) 2437 errors ++; 2438 } 2439 else 2440 errors = valid_path("cupsFilter", pathprog, errors, verbose, warn); 2441 } 2442 } 2443 2444 /* 2445 * cupsFilter2 2446 */ 2447 2448 for (attr = ppdFindAttr(ppd, "cupsFilter2", NULL); 2449 attr; 2450 attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) 2451 { 2452 if (strcmp(attr->name, "cupsFilter2")) 2453 { 2454 if (!warn && !errors && !verbose) 2455 _cupsLangPuts(stdout, _(" FAIL")); 2456 2457 if (verbose >= 0) 2458 _cupsLangPrintf(stdout, 2459 _(" %s Bad spelling of %s - should be %s."), 2460 prefix, attr->name, "cupsFilter2"); 2461 2462 if (!warn) 2463 errors ++; 2464 } 2465 2466 if (!attr->value || 2467 sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]", 2468 super, type, dstsuper, dsttype, &cost, program) != 6) 2469 { 2470 if (!warn && !errors && !verbose) 2471 _cupsLangPuts(stdout, _(" FAIL")); 2472 2473 if (verbose >= 0) 2474 _cupsLangPrintf(stdout, 2475 _(" %s Bad cupsFilter2 value \"%s\"."), 2476 prefix, attr->value); 2477 2478 if (!warn) 2479 errors ++; 2480 } 2481 else if (strcmp(program, "-")) 2482 { 2483 if (strncmp(program, "maxsize(", 8) && 2484 (ptr = strchr(program + 8, ')')) != NULL) 2485 { 2486 ptr ++; 2487 while (_cups_isspace(*ptr)) 2488 ptr ++; 2489 2490 _cups_strcpy(program, ptr); 2491 } 2492 2493 if (program[0] == '/') 2494 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program); 2495 else 2496 { 2497 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL) 2498 ptr = CUPS_SERVERBIN; 2499 2500 if (*ptr == '/' || !*root) 2501 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr, 2502 program); 2503 else 2504 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr, 2505 program); 2506 } 2507 2508 if (stat(pathprog, &fileinfo)) 2509 { 2510 if (!warn && !errors && !verbose) 2511 _cupsLangPuts(stdout, _(" FAIL")); 2512 2513 if (verbose >= 0) 2514 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2515 prefix, "cupsFilter2", pathprog); 2516 2517 if (!warn) 2518 errors ++; 2519 } 2520 else if (fileinfo.st_uid != 0 || 2521 (fileinfo.st_mode & MODE_WRITE) || 2522 (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM) 2523 { 2524 if (!warn && !errors && !verbose) 2525 _cupsLangPuts(stdout, _(" FAIL")); 2526 2527 if (verbose >= 0) 2528 _cupsLangPrintf(stdout, 2529 _(" %s Bad permissions on %s file \"%s\"."), 2530 prefix, "cupsFilter2", pathprog); 2531 2532 if (!warn) 2533 errors ++; 2534 } 2535 else 2536 errors = valid_path("cupsFilter2", pathprog, errors, verbose, warn); 2537 } 2538 } 2539 2540 /* 2541 * cupsPreFilter 2542 */ 2543 2544 for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL); 2545 attr; 2546 attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) 2547 { 2548 if (strcmp(attr->name, "cupsPreFilter")) 2549 { 2550 if (!warn && !errors && !verbose) 2551 _cupsLangPuts(stdout, _(" FAIL")); 2552 2553 if (verbose >= 0) 2554 _cupsLangPrintf(stdout, 2555 _(" %s Bad spelling of %s - should be %s."), 2556 prefix, attr->name, "cupsPreFilter"); 2557 2558 if (!warn) 2559 errors ++; 2560 } 2561 2562 if (!attr->value || 2563 sscanf(attr->value, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, 2564 &cost, program) != 4) 2565 { 2566 if (!warn && !errors && !verbose) 2567 _cupsLangPuts(stdout, _(" FAIL")); 2568 2569 if (verbose >= 0) 2570 _cupsLangPrintf(stdout, 2571 _(" %s Bad cupsPreFilter value \"%s\"."), 2572 prefix, attr->value ? attr->value : ""); 2573 2574 if (!warn) 2575 errors ++; 2576 } 2577 else if (strcmp(program, "-")) 2578 { 2579 if (program[0] == '/') 2580 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program); 2581 else 2582 { 2583 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL) 2584 ptr = CUPS_SERVERBIN; 2585 2586 if (*ptr == '/' || !*root) 2587 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr, 2588 program); 2589 else 2590 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr, 2591 program); 2592 } 2593 2594 if (stat(pathprog, &fileinfo)) 2595 { 2596 if (!warn && !errors && !verbose) 2597 _cupsLangPuts(stdout, _(" FAIL")); 2598 2599 if (verbose >= 0) 2600 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2601 prefix, "cupsPreFilter", pathprog); 2602 2603 if (!warn) 2604 errors ++; 2605 } 2606 else if (fileinfo.st_uid != 0 || 2607 (fileinfo.st_mode & MODE_WRITE) || 2608 (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM) 2609 { 2610 if (!warn && !errors && !verbose) 2611 _cupsLangPuts(stdout, _(" FAIL")); 2612 2613 if (verbose >= 0) 2614 _cupsLangPrintf(stdout, 2615 _(" %s Bad permissions on %s file \"%s\"."), 2616 prefix, "cupsPreFilter", pathprog); 2617 2618 if (!warn) 2619 errors ++; 2620 } 2621 else 2622 errors = valid_path("cupsPreFilter", pathprog, errors, verbose, warn); 2623 } 2624 } 2625 2626#ifdef __APPLE__ 2627 /* 2628 * APDialogExtension 2629 */ 2630 2631 for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL); 2632 attr != NULL; 2633 attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL)) 2634 { 2635 if (strcmp(attr->name, "APDialogExtension")) 2636 { 2637 if (!warn && !errors && !verbose) 2638 _cupsLangPuts(stdout, _(" FAIL")); 2639 2640 if (verbose >= 0) 2641 _cupsLangPrintf(stdout, 2642 _(" %s Bad spelling of %s - should be %s."), 2643 prefix, attr->name, "APDialogExtension"); 2644 2645 if (!warn) 2646 errors ++; 2647 } 2648 2649 snprintf(pathprog, sizeof(pathprog), "%s%s", root, 2650 attr->value ? attr->value : "(null)"); 2651 2652 if (!attr->value || stat(pathprog, &fileinfo)) 2653 { 2654 if (!warn && !errors && !verbose) 2655 _cupsLangPuts(stdout, _(" FAIL")); 2656 2657 if (verbose >= 0) 2658 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2659 prefix, "APDialogExtension", pathprog); 2660 2661 if (!warn) 2662 errors ++; 2663 } 2664 else if (fileinfo.st_uid != 0 || 2665 (fileinfo.st_mode & MODE_WRITE) || 2666 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY) 2667 { 2668 if (!warn && !errors && !verbose) 2669 _cupsLangPuts(stdout, _(" FAIL")); 2670 2671 if (verbose >= 0) 2672 _cupsLangPrintf(stdout, 2673 _(" %s Bad permissions on %s file \"%s\"."), 2674 prefix, "APDialogExtension", pathprog); 2675 2676 if (!warn) 2677 errors ++; 2678 } 2679 else 2680 errors = valid_path("APDialogExtension", pathprog, errors, verbose, 2681 warn); 2682 } 2683 2684 /* 2685 * APPrinterIconPath 2686 */ 2687 2688 if ((attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL) 2689 { 2690 if (strcmp(attr->name, "APPrinterIconPath")) 2691 { 2692 if (!warn && !errors && !verbose) 2693 _cupsLangPuts(stdout, _(" FAIL")); 2694 2695 if (verbose >= 0) 2696 _cupsLangPrintf(stdout, 2697 _(" %s Bad spelling of %s - should be %s."), 2698 prefix, attr->name, "APPrinterIconPath"); 2699 2700 if (!warn) 2701 errors ++; 2702 } 2703 2704 snprintf(pathprog, sizeof(pathprog), "%s%s", root, 2705 attr->value ? attr->value : "(null)"); 2706 2707 if (!attr->value || stat(pathprog, &fileinfo)) 2708 { 2709 if (!warn && !errors && !verbose) 2710 _cupsLangPuts(stdout, _(" FAIL")); 2711 2712 if (verbose >= 0) 2713 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2714 prefix, "APPrinterIconPath", pathprog); 2715 2716 if (!warn) 2717 errors ++; 2718 } 2719 else if (fileinfo.st_uid != 0 || 2720 (fileinfo.st_mode & MODE_WRITE) || 2721 (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE) 2722 { 2723 if (!warn && !errors && !verbose) 2724 _cupsLangPuts(stdout, _(" FAIL")); 2725 2726 if (verbose >= 0) 2727 _cupsLangPrintf(stdout, 2728 _(" %s Bad permissions on %s file \"%s\"."), 2729 prefix, "APPrinterIconPath", pathprog); 2730 2731 if (!warn) 2732 errors ++; 2733 } 2734 else 2735 errors = valid_path("APPrinterIconPath", pathprog, errors, verbose, 2736 warn); 2737 } 2738 2739 /* 2740 * APPrinterLowInkTool 2741 */ 2742 2743 if ((attr = ppdFindAttr(ppd, "APPrinterLowInkTool", NULL)) != NULL) 2744 { 2745 if (strcmp(attr->name, "APPrinterLowInkTool")) 2746 { 2747 if (!warn && !errors && !verbose) 2748 _cupsLangPuts(stdout, _(" FAIL")); 2749 2750 if (verbose >= 0) 2751 _cupsLangPrintf(stdout, 2752 _(" %s Bad spelling of %s - should be %s."), 2753 prefix, attr->name, "APPrinterLowInkTool"); 2754 2755 if (!warn) 2756 errors ++; 2757 } 2758 2759 snprintf(pathprog, sizeof(pathprog), "%s%s", root, 2760 attr->value ? attr->value : "(null)"); 2761 2762 if (!attr->value || stat(pathprog, &fileinfo)) 2763 { 2764 if (!warn && !errors && !verbose) 2765 _cupsLangPuts(stdout, _(" FAIL")); 2766 2767 if (verbose >= 0) 2768 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2769 prefix, "APPrinterLowInkTool", pathprog); 2770 2771 if (!warn) 2772 errors ++; 2773 } 2774 else if (fileinfo.st_uid != 0 || 2775 (fileinfo.st_mode & MODE_WRITE) || 2776 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY) 2777 { 2778 if (!warn && !errors && !verbose) 2779 _cupsLangPuts(stdout, _(" FAIL")); 2780 2781 if (verbose >= 0) 2782 _cupsLangPrintf(stdout, 2783 _(" %s Bad permissions on %s file \"%s\"."), 2784 prefix, "APPrinterLowInkTool", pathprog); 2785 2786 if (!warn) 2787 errors ++; 2788 } 2789 else 2790 errors = valid_path("APPrinterLowInkTool", pathprog, errors, verbose, 2791 warn); 2792 } 2793 2794 /* 2795 * APPrinterUtilityPath 2796 */ 2797 2798 if ((attr = ppdFindAttr(ppd, "APPrinterUtilityPath", NULL)) != NULL) 2799 { 2800 if (strcmp(attr->name, "APPrinterUtilityPath")) 2801 { 2802 if (!warn && !errors && !verbose) 2803 _cupsLangPuts(stdout, _(" FAIL")); 2804 2805 if (verbose >= 0) 2806 _cupsLangPrintf(stdout, 2807 _(" %s Bad spelling of %s - should be %s."), 2808 prefix, attr->name, "APPrinterUtilityPath"); 2809 2810 if (!warn) 2811 errors ++; 2812 } 2813 2814 snprintf(pathprog, sizeof(pathprog), "%s%s", root, 2815 attr->value ? attr->value : "(null)"); 2816 2817 if (!attr->value || stat(pathprog, &fileinfo)) 2818 { 2819 if (!warn && !errors && !verbose) 2820 _cupsLangPuts(stdout, _(" FAIL")); 2821 2822 if (verbose >= 0) 2823 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2824 prefix, "APPrinterUtilityPath", pathprog); 2825 2826 if (!warn) 2827 errors ++; 2828 } 2829 else if (fileinfo.st_uid != 0 || 2830 (fileinfo.st_mode & MODE_WRITE) || 2831 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY) 2832 { 2833 if (!warn && !errors && !verbose) 2834 _cupsLangPuts(stdout, _(" FAIL")); 2835 2836 if (verbose >= 0) 2837 _cupsLangPrintf(stdout, 2838 _(" %s Bad permissions on %s file \"%s\"."), 2839 prefix, "APPrinterUtilityPath", pathprog); 2840 2841 if (!warn) 2842 errors ++; 2843 } 2844 else 2845 errors = valid_path("APPrinterUtilityPath", pathprog, errors, verbose, 2846 warn); 2847 } 2848 2849 /* 2850 * APScanAppBundleID and APScanAppPath 2851 */ 2852 2853 if ((attr = ppdFindAttr(ppd, "APScanAppPath", NULL)) != NULL) 2854 { 2855 if (strcmp(attr->name, "APScanAppPath")) 2856 { 2857 if (!warn && !errors && !verbose) 2858 _cupsLangPuts(stdout, _(" FAIL")); 2859 2860 if (verbose >= 0) 2861 _cupsLangPrintf(stdout, 2862 _(" %s Bad spelling of %s - should be %s."), 2863 prefix, attr->name, "APScanAppPath"); 2864 2865 if (!warn) 2866 errors ++; 2867 } 2868 2869 if (!attr->value || stat(attr->value, &fileinfo)) 2870 { 2871 if (!warn && !errors && !verbose) 2872 _cupsLangPuts(stdout, _(" FAIL")); 2873 2874 if (verbose >= 0) 2875 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2876 prefix, "APScanAppPath", 2877 attr->value ? attr->value : "<NULL>"); 2878 2879 if (!warn) 2880 errors ++; 2881 } 2882 else if (fileinfo.st_uid != 0 || 2883 (fileinfo.st_mode & MODE_WRITE) || 2884 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY) 2885 { 2886 if (!warn && !errors && !verbose) 2887 _cupsLangPuts(stdout, _(" FAIL")); 2888 2889 if (verbose >= 0) 2890 _cupsLangPrintf(stdout, 2891 _(" %s Bad permissions on %s file \"%s\"."), 2892 prefix, "APScanAppPath", attr->value); 2893 2894 if (!warn) 2895 errors ++; 2896 } 2897 else 2898 errors = valid_path("APScanAppPath", attr->value, errors, verbose, 2899 warn); 2900 2901 if (ppdFindAttr(ppd, "APScanAppBundleID", NULL)) 2902 { 2903 if (!warn && !errors && !verbose) 2904 _cupsLangPuts(stdout, _(" FAIL")); 2905 2906 if (verbose >= 0) 2907 _cupsLangPrintf(stdout, _(" %s Cannot provide both " 2908 "APScanAppPath and APScanAppBundleID."), 2909 prefix); 2910 2911 if (!warn) 2912 errors ++; 2913 } 2914 } 2915#endif /* __APPLE__ */ 2916 2917 return (errors); 2918} 2919 2920 2921/* 2922 * 'check_profiles()' - Check ICC color profiles in the PPD file. 2923 */ 2924 2925static int /* O - Errors found */ 2926check_profiles(ppd_file_t *ppd, /* I - PPD file */ 2927 const char *root, /* I - Root directory */ 2928 int errors, /* I - Errors found */ 2929 int verbose, /* I - Verbosity level */ 2930 int warn) /* I - Warnings only? */ 2931{ 2932 int i; /* Looping var */ 2933 ppd_attr_t *attr; /* PPD attribute */ 2934 const char *ptr; /* Pointer into string */ 2935 const char *prefix; /* WARN/FAIL prefix */ 2936 char filename[1024]; /* Profile filename */ 2937 struct stat fileinfo; /* File information */ 2938 int num_profiles = 0; /* Number of profiles */ 2939 unsigned hash, /* Current hash value */ 2940 hashes[1000]; /* Hash values of profile names */ 2941 const char *specs[1000]; /* Specifiers for profiles */ 2942 2943 2944 prefix = warn ? " WARN " : "**FAIL**"; 2945 2946 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); 2947 attr; 2948 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) 2949 { 2950 /* 2951 * Check for valid selector... 2952 */ 2953 2954 for (i = 0, ptr = strchr(attr->spec, '.'); ptr; ptr = strchr(ptr + 1, '.')) 2955 i ++; 2956 2957 if (!attr->value || i < 2) 2958 { 2959 if (!warn && !errors && !verbose) 2960 _cupsLangPuts(stdout, _(" FAIL")); 2961 2962 if (verbose >= 0) 2963 _cupsLangPrintf(stdout, 2964 _(" %s Bad cupsICCProfile %s."), 2965 prefix, attr->spec); 2966 2967 if (!warn) 2968 errors ++; 2969 2970 continue; 2971 } 2972 2973 /* 2974 * Check for valid profile filename... 2975 */ 2976 2977 if (attr->value[0] == '/') 2978 snprintf(filename, sizeof(filename), "%s%s", root, attr->value); 2979 else 2980 { 2981 if ((ptr = getenv("CUPS_DATADIR")) == NULL) 2982 ptr = CUPS_DATADIR; 2983 2984 if (*ptr == '/' || !*root) 2985 snprintf(filename, sizeof(filename), "%s%s/profiles/%s", root, ptr, 2986 attr->value); 2987 else 2988 snprintf(filename, sizeof(filename), "%s/%s/profiles/%s", root, ptr, 2989 attr->value); 2990 } 2991 2992 if (stat(filename, &fileinfo)) 2993 { 2994 if (!warn && !errors && !verbose) 2995 _cupsLangPuts(stdout, _(" FAIL")); 2996 2997 if (verbose >= 0) 2998 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."), 2999 prefix, "cupsICCProfile", filename); 3000 3001 if (!warn) 3002 errors ++; 3003 } 3004 else if (fileinfo.st_uid != 0 || 3005 (fileinfo.st_mode & MODE_WRITE) || 3006 (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE) 3007 { 3008 if (!warn && !errors && !verbose) 3009 _cupsLangPuts(stdout, _(" FAIL")); 3010 3011 if (verbose >= 0) 3012 _cupsLangPrintf(stdout, 3013 _(" %s Bad permissions on %s file \"%s\"."), 3014 prefix, "cupsICCProfile", filename); 3015 3016 if (!warn) 3017 errors ++; 3018 } 3019 else 3020 errors = valid_path("cupsICCProfile", filename, errors, verbose, warn); 3021 3022 /* 3023 * Check for hash collisions... 3024 */ 3025 3026 hash = _ppdHashName(attr->spec); 3027 3028 if (num_profiles > 0) 3029 { 3030 for (i = 0; i < num_profiles; i ++) 3031 if (hashes[i] == hash) 3032 break; 3033 3034 if (i < num_profiles) 3035 { 3036 if (!warn && !errors && !verbose) 3037 _cupsLangPuts(stdout, _(" FAIL")); 3038 3039 if (verbose >= 0) 3040 _cupsLangPrintf(stdout, 3041 _(" %s cupsICCProfile %s hash value " 3042 "collides with %s."), prefix, attr->spec, 3043 specs[i]); 3044 3045 if (!warn) 3046 errors ++; 3047 } 3048 } 3049 3050 /* 3051 * Remember up to 1000 profiles... 3052 */ 3053 3054 if (num_profiles < 1000) 3055 { 3056 hashes[num_profiles] = hash; 3057 specs[num_profiles] = attr->spec; 3058 num_profiles ++; 3059 } 3060 } 3061 3062 return (errors); 3063} 3064 3065 3066/* 3067 * 'check_sizes()' - Check media sizes in the PPD file. 3068 */ 3069 3070static int /* O - Errors found */ 3071check_sizes(ppd_file_t *ppd, /* I - PPD file */ 3072 int errors, /* I - Errors found */ 3073 int verbose, /* I - Verbosity level */ 3074 int warn) /* I - Warnings only? */ 3075{ 3076 int i; /* Looping var */ 3077 ppd_size_t *size; /* Current size */ 3078 int width, /* Custom width */ 3079 length; /* Custom length */ 3080 const char *prefix; /* WARN/FAIL prefix */ 3081 ppd_option_t *page_size, /* PageSize option */ 3082 *page_region; /* PageRegion option */ 3083 _pwg_media_t *pwg_media; /* PWG media */ 3084 char buf[PPD_MAX_NAME]; /* PapeSize name that is supposed to be */ 3085 const char *ptr; /* Pointer into string */ 3086 int width_2540ths, /* PageSize width in 2540ths */ 3087 length_2540ths; /* PageSize length in 2540ths */ 3088 int is_ok; /* Flag for PageSize name verification */ 3089 double width_tmp, /* Width after rounded up */ 3090 length_tmp, /* Length after rounded up */ 3091 width_inch, /* Width in inches */ 3092 length_inch, /* Length in inches */ 3093 width_mm, /* Width in millimeters */ 3094 length_mm; /* Length in millimeters */ 3095 3096 3097 prefix = warn ? " WARN " : "**FAIL**"; 3098 3099 if ((page_size = ppdFindOption(ppd, "PageSize")) == NULL && warn != 2) 3100 { 3101 if (!warn && !errors && !verbose) 3102 _cupsLangPuts(stdout, _(" FAIL")); 3103 3104 if (verbose >= 0) 3105 _cupsLangPrintf(stdout, 3106 _(" %s Missing REQUIRED PageSize option.\n" 3107 " REF: Page 99, section 5.14."), 3108 prefix); 3109 3110 if (!warn) 3111 errors ++; 3112 } 3113 3114 if ((page_region = ppdFindOption(ppd, "PageRegion")) == NULL && warn != 2) 3115 { 3116 if (!warn && !errors && !verbose) 3117 _cupsLangPuts(stdout, _(" FAIL")); 3118 3119 if (verbose >= 0) 3120 _cupsLangPrintf(stdout, 3121 _(" %s Missing REQUIRED PageRegion option.\n" 3122 " REF: Page 100, section 5.14."), 3123 prefix); 3124 3125 if (!warn) 3126 errors ++; 3127 } 3128 3129 for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++) 3130 { 3131 /* 3132 * Check that the size name is standard... 3133 */ 3134 3135 if (!strcmp(size->name, "Custom")) 3136 { 3137 /* 3138 * Skip custom page size... 3139 */ 3140 3141 continue; 3142 } 3143 3144 if (warn != 2 && size->name[0] == 'w' && 3145 sscanf(size->name, "w%dh%d", &width, &length) == 2) 3146 { 3147 /* 3148 * Validate device-specific size wNNNhNNN should have proper width and 3149 * length... 3150 */ 3151 3152 if (fabs(width - size->width) >= 1.0 || 3153 fabs(length - size->length) >= 1.0) 3154 { 3155 if (!warn && !errors && !verbose) 3156 _cupsLangPuts(stdout, _(" FAIL")); 3157 3158 if (verbose >= 0) 3159 _cupsLangPrintf(stdout, 3160 _(" %s Size \"%s\" has unexpected dimensions " 3161 "(%gx%g)."), 3162 prefix, size->name, size->width, size->length); 3163 3164 if (!warn) 3165 errors ++; 3166 } 3167 } 3168 3169 /* 3170 * Verify that the size is defined for both PageSize and PageRegion... 3171 */ 3172 3173 if (warn != 2 && !ppdFindChoice(page_size, size->name)) 3174 { 3175 if (!warn && !errors && !verbose) 3176 _cupsLangPuts(stdout, _(" FAIL")); 3177 3178 if (verbose >= 0) 3179 _cupsLangPrintf(stdout, 3180 _(" %s Size \"%s\" defined for %s but not for " 3181 "%s."), 3182 prefix, size->name, "PageRegion", "PageSize"); 3183 3184 if (!warn) 3185 errors ++; 3186 } 3187 else if (warn != 2 && !ppdFindChoice(page_region, size->name)) 3188 { 3189 if (!warn && !errors && !verbose) 3190 _cupsLangPuts(stdout, _(" FAIL")); 3191 3192 if (verbose >= 0) 3193 _cupsLangPrintf(stdout, 3194 _(" %s Size \"%s\" defined for %s but not for " 3195 "%s."), 3196 prefix, size->name, "PageSize", "PageRegion"); 3197 3198 if (!warn) 3199 errors ++; 3200 } 3201 3202 /* 3203 * Verify that the size name is Adobe standard name if it's a standard size 3204 * and the dimentional name if it's not a standard size. Suffix should be 3205 * .Fullbleed, etc., or numeric, e.g., Letter, Letter.Fullbleed, 3206 * Letter.Transverse, Letter1, Letter2, 4x8, 55x91mm, 55x91mm.Fullbleed, etc. 3207 */ 3208 3209 if (warn != 0) 3210 { 3211 is_ok = 1; 3212 width_2540ths = (size->length > size->width) ? 3213 PWG_FROM_POINTS(size->width) : 3214 PWG_FROM_POINTS(size->length); 3215 length_2540ths = (size->length > size->width) ? 3216 PWG_FROM_POINTS(size->length) : 3217 PWG_FROM_POINTS(size->width); 3218 pwg_media = pwgMediaForSize(width_2540ths, length_2540ths); 3219 3220 if (pwg_media && 3221 (fabs(pwg_media->width - width_2540ths) > 34 || 3222 fabs(pwg_media->length - length_2540ths) > 34)) 3223 pwg_media = NULL; /* Only flag matches within a point */ 3224 3225 if (pwg_media && pwg_media->ppd && 3226 (pwg_media->ppd[0] < 'a' || pwg_media->ppd[0] > 'z')) 3227 { 3228 size_t ppdlen = strlen(pwg_media->ppd); 3229 /* Length of standard PPD name */ 3230 3231 strlcpy(buf, pwg_media->ppd, sizeof(buf)); 3232 3233 if (strcmp(size->name, buf) && size->width > size->length) 3234 { 3235 if (!strcmp(pwg_media->ppd, "DoublePostcardRotated")) 3236 strlcpy(buf, "DoublePostcard", sizeof(buf)); 3237 else if (strstr(size->name, ".Transverse")) 3238 snprintf(buf, sizeof(buf), "%s.Transverse", pwg_media->ppd); 3239 else 3240 snprintf(buf, sizeof(buf), "%sRotated", pwg_media->ppd); 3241 3242 ppdlen = strlen(buf); 3243 } 3244 3245 if (size->left == 0 && size->bottom == 0 && 3246 size->right == size->width && size->top == size->length) 3247 { 3248 strlcat(buf, ".Fullbleed", sizeof(buf) - strlen(buf)); 3249 if (_cups_strcasecmp(size->name, buf)) 3250 { 3251 /* 3252 * Allow an additional qualifier such as ".WithTab"... 3253 */ 3254 3255 size_t buflen = strlen(buf);/* Length of full bleed name */ 3256 3257 if (_cups_strncasecmp(size->name, buf, buflen) || 3258 size->name[buflen] != '.') 3259 is_ok = 0; 3260 } 3261 } 3262 else if (!strncmp(size->name, pwg_media->ppd, ppdlen)) 3263 { 3264 /* 3265 * Check for a proper qualifier (number, "Small", or .something)... 3266 */ 3267 3268 ptr = size->name + ppdlen; 3269 3270 if (isdigit(*ptr & 255)) 3271 { 3272 for (ptr ++; *ptr; ptr ++) 3273 { 3274 if (!isdigit(*ptr & 255)) 3275 { 3276 is_ok = 0; 3277 break; 3278 } 3279 } 3280 } 3281 else if (*ptr != '.' && *ptr && strcmp(ptr, "Small")) 3282 is_ok = 0; 3283 } 3284 else 3285 { 3286 /* 3287 * Check for EnvSizeName as well... 3288 */ 3289 3290 if (strncmp(pwg_media->ppd, "Env", 3) && 3291 !strncmp(size->name, "Env", 3)) 3292 snprintf(buf, sizeof(buf), "Env%s", pwg_media->ppd); 3293 3294 if (strcmp(size->name, buf)) 3295 is_ok = 0; 3296 } 3297 3298 if (!is_ok) 3299 _cupsLangPrintf(stdout, 3300 _(" %s Size \"%s\" should be the Adobe " 3301 "standard name \"%s\"."), 3302 prefix, size->name, buf); 3303 } 3304 else 3305 { 3306 width_tmp = (fabs(size->width - ceil(size->width)) < 0.1) ? 3307 ceil(size->width) : size->width; 3308 length_tmp = (fabs(size->length - ceil(size->length)) < 0.1) ? 3309 ceil(size->length) : size->length; 3310 3311 if (fmod(width_tmp, 9.0) == 0.0 && fmod(length_tmp, 9.0) == 0.0) 3312 { 3313 width_inch = width_tmp / 72.0; 3314 length_inch = length_tmp / 72.0; 3315 3316 snprintf(buf, sizeof(buf), "%gx%g", width_inch, length_inch); 3317 } 3318 else 3319 { 3320 width_mm = size->width / 72.0 * 25.4; 3321 length_mm = size->length / 72.0 * 25.4; 3322 3323 snprintf(buf, sizeof(buf), "%.0fx%.0fmm", width_mm, length_mm); 3324 } 3325 3326 if (size->left == 0 && size->bottom == 0 && 3327 size->right == size->width && size->top == size->length) 3328 strlcat(buf, ".Fullbleed", sizeof(buf)); 3329 else if (size->width > size->length) 3330 strlcat(buf, ".Transverse", sizeof(buf)); 3331 3332 if (_cups_strcasecmp(size->name, buf)) 3333 { 3334 size_t buflen = strlen(buf); 3335 /* Length of proposed name */ 3336 3337 if (_cups_strncasecmp(size->name, buf, buflen) || 3338 (strcmp(size->name + buflen, "in") && 3339 size->name[buflen] != '.')) 3340 { 3341 char altbuf[PPD_MAX_NAME]; 3342 /* Alternate "wNNNhNNN" name */ 3343 size_t altlen; /* Length of alternate name */ 3344 3345 snprintf(altbuf, sizeof(altbuf), "w%.0fh%.0f", size->width, 3346 size->length); 3347 altlen = strlen(altbuf); 3348 if (_cups_strncasecmp(size->name, altbuf, altlen) || 3349 (size->name[altlen] && size->name[altlen] != '.')) 3350 _cupsLangPrintf(stdout, 3351 _(" %s Size \"%s\" should be \"%s\"."), 3352 prefix, size->name, buf); 3353 } 3354 } 3355 } 3356 } 3357 } 3358 3359 return (errors); 3360} 3361 3362 3363/* 3364 * 'check_translations()' - Check translations in the PPD file. 3365 */ 3366 3367static int /* O - Errors found */ 3368check_translations(ppd_file_t *ppd, /* I - PPD file */ 3369 int errors, /* I - Errors found */ 3370 int verbose, /* I - Verbosity level */ 3371 int warn) /* I - Warnings only? */ 3372{ 3373 int j; /* Looping var */ 3374 ppd_attr_t *attr; /* PPD attribute */ 3375 cups_array_t *languages; /* Array of languages */ 3376 int langlen; /* Length of language */ 3377 char *language, /* Current language */ 3378 keyword[PPD_MAX_NAME], /* Localization keyword (full) */ 3379 llkeyword[PPD_MAX_NAME],/* Localization keyword (base) */ 3380 ckeyword[PPD_MAX_NAME], /* Custom option keyword (full) */ 3381 cllkeyword[PPD_MAX_NAME]; 3382 /* Custom option keyword (base) */ 3383 ppd_option_t *option; /* Standard UI option */ 3384 ppd_coption_t *coption; /* Custom option */ 3385 ppd_cparam_t *cparam; /* Custom parameter */ 3386 char ll[3]; /* Base language */ 3387 const char *prefix; /* WARN/FAIL prefix */ 3388 const char *text; /* Pointer into UI text */ 3389 3390 3391 prefix = warn ? " WARN " : "**FAIL**"; 3392 3393 if ((languages = _ppdGetLanguages(ppd)) != NULL) 3394 { 3395 /* 3396 * This file contains localizations, check them... 3397 */ 3398 3399 for (language = (char *)cupsArrayFirst(languages); 3400 language; 3401 language = (char *)cupsArrayNext(languages)) 3402 { 3403 langlen = (int)strlen(language); 3404 if (langlen != 2 && langlen != 5) 3405 { 3406 if (!warn && !errors && !verbose) 3407 _cupsLangPuts(stdout, _(" FAIL")); 3408 3409 if (verbose >= 0) 3410 _cupsLangPrintf(stdout, 3411 _(" %s Bad language \"%s\"."), 3412 prefix, language); 3413 3414 if (!warn) 3415 errors ++; 3416 3417 continue; 3418 } 3419 3420 if (!strcmp(language, "en")) 3421 continue; 3422 3423 strlcpy(ll, language, sizeof(ll)); 3424 3425 /* 3426 * Loop through all options and choices... 3427 */ 3428 3429 for (option = ppdFirstOption(ppd); 3430 option; 3431 option = ppdNextOption(ppd)) 3432 { 3433 if (!strcmp(option->keyword, "PageRegion")) 3434 continue; 3435 3436 snprintf(keyword, sizeof(keyword), "%s.Translation", language); 3437 snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll); 3438 3439 if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL && 3440 (attr = ppdFindAttr(ppd, llkeyword, option->keyword)) == NULL) 3441 { 3442 if (!warn && !errors && !verbose) 3443 _cupsLangPuts(stdout, _(" FAIL")); 3444 3445 if (verbose >= 0) 3446 _cupsLangPrintf(stdout, 3447 _(" %s Missing \"%s\" translation " 3448 "string for option %s."), 3449 prefix, language, option->keyword); 3450 3451 if (!warn) 3452 errors ++; 3453 } 3454 else if (!valid_utf8(attr->text)) 3455 { 3456 if (!warn && !errors && !verbose) 3457 _cupsLangPuts(stdout, _(" FAIL")); 3458 3459 if (verbose >= 0) 3460 _cupsLangPrintf(stdout, 3461 _(" %s Bad UTF-8 \"%s\" translation " 3462 "string for option %s."), 3463 prefix, language, option->keyword); 3464 3465 if (!warn) 3466 errors ++; 3467 } 3468 3469 snprintf(keyword, sizeof(keyword), "%s.%s", language, 3470 option->keyword); 3471 snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll, 3472 option->keyword); 3473 3474 for (j = 0; j < option->num_choices; j ++) 3475 { 3476 /* 3477 * First see if this choice is a number; if so, don't require 3478 * translation... 3479 */ 3480 3481 for (text = option->choices[j].text; *text; text ++) 3482 if (!strchr("0123456789-+.", *text)) 3483 break; 3484 3485 if (!*text) 3486 continue; 3487 3488 /* 3489 * Check custom choices differently... 3490 */ 3491 3492 if (!_cups_strcasecmp(option->choices[j].choice, "Custom") && 3493 (coption = ppdFindCustomOption(ppd, 3494 option->keyword)) != NULL) 3495 { 3496 snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s", 3497 language, option->keyword); 3498 3499 if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL && 3500 !valid_utf8(attr->text)) 3501 { 3502 if (!warn && !errors && !verbose) 3503 _cupsLangPuts(stdout, _(" FAIL")); 3504 3505 if (verbose >= 0) 3506 _cupsLangPrintf(stdout, 3507 _(" %s Bad UTF-8 \"%s\" " 3508 "translation string for option %s, " 3509 "choice %s."), 3510 prefix, language, 3511 ckeyword + 1 + strlen(language), 3512 "True"); 3513 3514 if (!warn) 3515 errors ++; 3516 } 3517 3518 if (_cups_strcasecmp(option->keyword, "PageSize")) 3519 { 3520 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params); 3521 cparam; 3522 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) 3523 { 3524 snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s", 3525 language, option->keyword); 3526 snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s", 3527 ll, option->keyword); 3528 3529 if ((attr = ppdFindAttr(ppd, ckeyword, 3530 cparam->name)) == NULL && 3531 (attr = ppdFindAttr(ppd, cllkeyword, 3532 cparam->name)) == NULL) 3533 { 3534 if (!warn && !errors && !verbose) 3535 _cupsLangPuts(stdout, _(" FAIL")); 3536 3537 if (verbose >= 0) 3538 _cupsLangPrintf(stdout, 3539 _(" %s Missing \"%s\" " 3540 "translation string for option %s, " 3541 "choice %s."), 3542 prefix, language, 3543 ckeyword + 1 + strlen(language), 3544 cparam->name); 3545 3546 if (!warn) 3547 errors ++; 3548 } 3549 else if (!valid_utf8(attr->text)) 3550 { 3551 if (!warn && !errors && !verbose) 3552 _cupsLangPuts(stdout, _(" FAIL")); 3553 3554 if (verbose >= 0) 3555 _cupsLangPrintf(stdout, 3556 _(" %s Bad UTF-8 \"%s\" " 3557 "translation string for option %s, " 3558 "choice %s."), 3559 prefix, language, 3560 ckeyword + 1 + strlen(language), 3561 cparam->name); 3562 3563 if (!warn) 3564 errors ++; 3565 } 3566 } 3567 } 3568 } 3569 else if ((attr = ppdFindAttr(ppd, keyword, 3570 option->choices[j].choice)) == NULL && 3571 (attr = ppdFindAttr(ppd, llkeyword, 3572 option->choices[j].choice)) == NULL) 3573 { 3574 if (!warn && !errors && !verbose) 3575 _cupsLangPuts(stdout, _(" FAIL")); 3576 3577 if (verbose >= 0) 3578 _cupsLangPrintf(stdout, 3579 _(" %s Missing \"%s\" " 3580 "translation string for option %s, " 3581 "choice %s."), 3582 prefix, language, option->keyword, 3583 option->choices[j].choice); 3584 3585 if (!warn) 3586 errors ++; 3587 } 3588 else if (!valid_utf8(attr->text)) 3589 { 3590 if (!warn && !errors && !verbose) 3591 _cupsLangPuts(stdout, _(" FAIL")); 3592 3593 if (verbose >= 0) 3594 _cupsLangPrintf(stdout, 3595 _(" %s Bad UTF-8 \"%s\" " 3596 "translation string for option %s, " 3597 "choice %s."), 3598 prefix, language, option->keyword, 3599 option->choices[j].choice); 3600 3601 if (!warn) 3602 errors ++; 3603 } 3604 } 3605 } 3606 } 3607 3608 /* 3609 * Verify that we have the base language for each localized one... 3610 */ 3611 3612 for (language = (char *)cupsArrayFirst(languages); 3613 language; 3614 language = (char *)cupsArrayNext(languages)) 3615 if (language[2]) 3616 { 3617 /* 3618 * Lookup the base language... 3619 */ 3620 3621 cupsArraySave(languages); 3622 3623 strlcpy(ll, language, sizeof(ll)); 3624 3625 if (!cupsArrayFind(languages, ll) && 3626 strcmp(ll, "zh") && strcmp(ll, "en")) 3627 { 3628 if (!warn && !errors && !verbose) 3629 _cupsLangPuts(stdout, _(" FAIL")); 3630 3631 if (verbose >= 0) 3632 _cupsLangPrintf(stdout, 3633 _(" %s No base translation \"%s\" " 3634 "is included in file."), prefix, ll); 3635 3636 if (!warn) 3637 errors ++; 3638 } 3639 3640 cupsArrayRestore(languages); 3641 } 3642 3643 /* 3644 * Free memory used for the languages... 3645 */ 3646 3647 _ppdFreeLanguages(languages); 3648 } 3649 3650 return (errors); 3651} 3652 3653 3654/* 3655 * 'show_conflicts()' - Show option conflicts in a PPD file. 3656 */ 3657 3658static void 3659show_conflicts(ppd_file_t *ppd, /* I - PPD to check */ 3660 const char *prefix) /* I - Prefix string */ 3661{ 3662 int i, j; /* Looping variables */ 3663 ppd_const_t *c; /* Current constraint */ 3664 ppd_option_t *o1, *o2; /* Options */ 3665 ppd_choice_t *c1, *c2; /* Choices */ 3666 3667 3668 /* 3669 * Loop through all of the UI constraints and report any options 3670 * that conflict... 3671 */ 3672 3673 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++) 3674 { 3675 /* 3676 * Grab pointers to the first option... 3677 */ 3678 3679 o1 = ppdFindOption(ppd, c->option1); 3680 3681 if (o1 == NULL) 3682 continue; 3683 else if (c->choice1[0] != '\0') 3684 { 3685 /* 3686 * This constraint maps to a specific choice. 3687 */ 3688 3689 c1 = ppdFindChoice(o1, c->choice1); 3690 } 3691 else 3692 { 3693 /* 3694 * This constraint applies to any choice for this option. 3695 */ 3696 3697 for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++) 3698 if (c1->marked) 3699 break; 3700 3701 if (j == 0 || 3702 !_cups_strcasecmp(c1->choice, "None") || 3703 !_cups_strcasecmp(c1->choice, "Off") || 3704 !_cups_strcasecmp(c1->choice, "False")) 3705 c1 = NULL; 3706 } 3707 3708 /* 3709 * Grab pointers to the second option... 3710 */ 3711 3712 o2 = ppdFindOption(ppd, c->option2); 3713 3714 if (o2 == NULL) 3715 continue; 3716 else if (c->choice2[0] != '\0') 3717 { 3718 /* 3719 * This constraint maps to a specific choice. 3720 */ 3721 3722 c2 = ppdFindChoice(o2, c->choice2); 3723 } 3724 else 3725 { 3726 /* 3727 * This constraint applies to any choice for this option. 3728 */ 3729 3730 for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++) 3731 if (c2->marked) 3732 break; 3733 3734 if (j == 0 || 3735 !_cups_strcasecmp(c2->choice, "None") || 3736 !_cups_strcasecmp(c2->choice, "Off") || 3737 !_cups_strcasecmp(c2->choice, "False")) 3738 c2 = NULL; 3739 } 3740 3741 /* 3742 * If both options are marked then there is a conflict... 3743 */ 3744 3745 if (c1 != NULL && c1->marked && c2 != NULL && c2->marked) 3746 _cupsLangPrintf(stdout, 3747 _(" %s \"%s %s\" conflicts with \"%s %s\"\n" 3748 " (constraint=\"%s %s %s %s\")."), 3749 prefix, o1->keyword, c1->choice, o2->keyword, c2->choice, 3750 c->option1, c->choice1, c->option2, c->choice2); 3751 } 3752} 3753 3754 3755/* 3756 * 'test_raster()' - Test PostScript commands for raster printers. 3757 */ 3758 3759static int /* O - 1 on success, 0 on failure */ 3760test_raster(ppd_file_t *ppd, /* I - PPD file */ 3761 int verbose) /* I - Verbosity */ 3762{ 3763 cups_page_header2_t header; /* Page header */ 3764 3765 3766 ppdMarkDefaults(ppd); 3767 if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0)) 3768 { 3769 if (!verbose) 3770 _cupsLangPuts(stdout, _(" FAIL")); 3771 3772 if (verbose >= 0) 3773 _cupsLangPrintf(stdout, 3774 _(" **FAIL** Default option code cannot be " 3775 "interpreted: %s"), cupsRasterErrorString()); 3776 3777 return (0); 3778 } 3779 3780 /* 3781 * Try a test of custom page size code, if available... 3782 */ 3783 3784 if (!ppdPageSize(ppd, "Custom.612x792")) 3785 return (1); 3786 3787 ppdMarkOption(ppd, "PageSize", "Custom.612x792"); 3788 3789 if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0)) 3790 { 3791 if (!verbose) 3792 _cupsLangPuts(stdout, _(" FAIL")); 3793 3794 if (verbose >= 0) 3795 _cupsLangPrintf(stdout, 3796 _(" **FAIL** Default option code cannot be " 3797 "interpreted: %s"), cupsRasterErrorString()); 3798 3799 return (0); 3800 } 3801 3802 return (1); 3803} 3804 3805 3806/* 3807 * 'usage()' - Show program usage. 3808 */ 3809 3810static void 3811usage(void) 3812{ 3813 _cupsLangPuts(stdout, _("Usage: cupstestppd [options] filename1.ppd[.gz] " 3814 "[... filenameN.ppd[.gz]]")); 3815 _cupsLangPuts(stdout, _(" program | cupstestppd [options] -")); 3816 _cupsLangPuts(stdout, ""); 3817 _cupsLangPuts(stdout, _("Options:")); 3818 _cupsLangPuts(stdout, ""); 3819 _cupsLangPuts(stdout, _(" -I {filename,filters,none,profiles}")); 3820 _cupsLangPuts(stdout, _(" Ignore specific warnings.")); 3821 _cupsLangPuts(stdout, _(" -R root-directory Set alternate root.")); 3822 _cupsLangPuts(stdout, _(" -W {all,none,constraints,defaults,duplex," 3823 "filters,profiles,sizes,translations}")); 3824 _cupsLangPuts(stdout, _(" Issue warnings instead of " 3825 "errors.")); 3826 _cupsLangPuts(stdout, _(" -q Run silently.")); 3827 _cupsLangPuts(stdout, _(" -r Use 'relaxed' open mode.")); 3828 _cupsLangPuts(stdout, _(" -v Be verbose.")); 3829 _cupsLangPuts(stdout, _(" -vv Be very verbose.")); 3830 3831 exit(ERROR_USAGE); 3832} 3833 3834 3835/* 3836 * 'valid_path()' - Check whether a path has the correct capitalization. 3837 */ 3838 3839static int /* O - Errors found */ 3840valid_path(const char *keyword, /* I - Keyword using path */ 3841 const char *path, /* I - Path to check */ 3842 int errors, /* I - Errors found */ 3843 int verbose, /* I - Verbosity level */ 3844 int warn) /* I - Warnings only? */ 3845{ 3846 cups_dir_t *dir; /* Current directory */ 3847 cups_dentry_t *dentry; /* Current directory entry */ 3848 char temp[1024], /* Temporary path */ 3849 *ptr; /* Pointer into temporary path */ 3850 const char *prefix; /* WARN/FAIL prefix */ 3851 3852 3853 prefix = warn ? " WARN " : "**FAIL**"; 3854 3855 /* 3856 * Loop over the components of the path, checking that the entry exists with 3857 * the same capitalization... 3858 */ 3859 3860 strlcpy(temp, path, sizeof(temp)); 3861 3862 while ((ptr = strrchr(temp, '/')) != NULL) 3863 { 3864 /* 3865 * Chop off the trailing component so temp == dirname and ptr == basename. 3866 */ 3867 3868 *ptr++ = '\0'; 3869 3870 /* 3871 * Try opening the directory containing the base name... 3872 */ 3873 3874 if (temp[0]) 3875 dir = cupsDirOpen(temp); 3876 else 3877 dir = cupsDirOpen("/"); 3878 3879 if (!dir) 3880 dentry = NULL; 3881 else 3882 { 3883 while ((dentry = cupsDirRead(dir)) != NULL) 3884 { 3885 if (!strcmp(dentry->filename, ptr)) 3886 break; 3887 } 3888 3889 cupsDirClose(dir); 3890 } 3891 3892 /* 3893 * Display an error if the filename doesn't exist with the same 3894 * capitalization... 3895 */ 3896 3897 if (!dentry) 3898 { 3899 if (!warn && !errors && !verbose) 3900 _cupsLangPuts(stdout, _(" FAIL")); 3901 3902 if (verbose >= 0) 3903 _cupsLangPrintf(stdout, 3904 _(" %s %s file \"%s\" has the wrong " 3905 "capitalization."), prefix, keyword, path); 3906 3907 if (!warn) 3908 errors ++; 3909 3910 break; 3911 } 3912 } 3913 3914 return (errors); 3915} 3916 3917 3918/* 3919 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text. 3920 */ 3921 3922static int /* O - 1 if valid, 0 if not */ 3923valid_utf8(const char *s) /* I - String to check */ 3924{ 3925 while (*s) 3926 { 3927 if (*s & 0x80) 3928 { 3929 /* 3930 * Check for valid UTF-8 sequence... 3931 */ 3932 3933 if ((*s & 0xc0) == 0x80) 3934 return (0); /* Illegal suffix byte */ 3935 else if ((*s & 0xe0) == 0xc0) 3936 { 3937 /* 3938 * 2-byte sequence... 3939 */ 3940 3941 s ++; 3942 3943 if ((*s & 0xc0) != 0x80) 3944 return (0); /* Missing suffix byte */ 3945 } 3946 else if ((*s & 0xf0) == 0xe0) 3947 { 3948 /* 3949 * 3-byte sequence... 3950 */ 3951 3952 s ++; 3953 3954 if ((*s & 0xc0) != 0x80) 3955 return (0); /* Missing suffix byte */ 3956 3957 s ++; 3958 3959 if ((*s & 0xc0) != 0x80) 3960 return (0); /* Missing suffix byte */ 3961 } 3962 else if ((*s & 0xf8) == 0xf0) 3963 { 3964 /* 3965 * 4-byte sequence... 3966 */ 3967 3968 s ++; 3969 3970 if ((*s & 0xc0) != 0x80) 3971 return (0); /* Missing suffix byte */ 3972 3973 s ++; 3974 3975 if ((*s & 0xc0) != 0x80) 3976 return (0); /* Missing suffix byte */ 3977 3978 s ++; 3979 3980 if ((*s & 0xc0) != 0x80) 3981 return (0); /* Missing suffix byte */ 3982 } 3983 else 3984 return (0); /* Bad sequence */ 3985 } 3986 3987 s ++; 3988 } 3989 3990 return (1); 3991} 3992 3993 3994/* 3995 * End of "$Id: cupstestppd.c 11560 2014-02-06 20:10:19Z msweet $". 3996 */ 3997