]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/cupstestppd.c
Copyright updates.
[thirdparty/cups.git] / systemv / cupstestppd.c
CommitLineData
4b0b2cf9 1/*
fa27cf64 2 * "$Id: cupstestppd.c,v 1.35 2005/01/03 19:29:59 mike Exp $"
4b0b2cf9 3 *
4 * PPD test program for the Common UNIX Printing System (CUPS).
5 *
fa27cf64 6 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
4b0b2cf9 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
01810936 18 * Hollywood, Maryland 20636 USA
4b0b2cf9 19 *
01810936 20 * Voice: (301) 373-9600
4b0b2cf9 21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * PostScript is a trademark of Adobe Systems, Inc.
25 *
26 * This file is subject to the Apple OS-Developed Software exception.
27 *
28 * Contents:
29 *
31e1c01a 30 * main() - Main entry for test program.
31 * show_conflicts() - Show option conflicts in a PPD file.
32 * usage() - Show program usage...
4b0b2cf9 33 */
34
35/*
36 * Include necessary headers...
37 */
38
39#include <cups/cups.h>
40#include <cups/string.h>
41#include <errno.h>
f249be22 42#include <stdlib.h>
4b0b2cf9 43
44
45/*
46 * Error codes...
47 */
48
49#define ERROR_NONE 0
50#define ERROR_USAGE 1
51#define ERROR_FILE_OPEN 2
52#define ERROR_PPD_FORMAT 3
53#define ERROR_CONFORMANCE 4
54
55
f249be22 56/*
57 * Local functions...
58 */
59
31e1c01a 60void show_conflicts(ppd_file_t *ppd);
f249be22 61void usage(void);
62
63
4b0b2cf9 64/*
65 * 'main()' - Main entry for test program.
66 */
67
68int /* O - Exit status */
69main(int argc, /* I - Number of command-line arguments */
70 char *argv[]) /* I - Command-line arguments */
71{
5c61431a 72 int i, j, k, m, n; /* Looping vars */
73 int len; /* Length of option name */
f249be22 74 char *opt; /* Option character */
75 const char *ptr; /* Pointer into string */
1391e7cb 76 int files; /* Number of files */
4b0b2cf9 77 int verbose; /* Want verbose output? */
78 int status; /* Exit status */
79 int errors; /* Number of conformance errors */
f9d01894 80 int ppdversion; /* PPD spec version in PPD file */
1391e7cb 81 ppd_status_t error; /* Status of ppdOpen*() */
82 int line; /* Line number for error */
4b0b2cf9 83 ppd_file_t *ppd; /* PPD file record */
f0e7bfbd 84 ppd_attr_t *attr; /* PPD attribute */
4b0b2cf9 85 ppd_size_t *size; /* Size record */
86 ppd_group_t *group; /* UI group */
87 ppd_option_t *option; /* Standard UI option */
5c61431a 88 ppd_group_t *group2; /* UI group */
89 ppd_option_t *option2; /* Standard UI option */
4b0b2cf9 90 ppd_choice_t *choice; /* Standard UI option choice */
91 static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
92 static char *sections[] = { "ANY", "DOCUMENT", "EXIT",
93 "JCL", "PAGE", "PROLOG" };
94
95
4b0b2cf9 96 /*
97 * Display PPD files for each file listed on the command-line...
98 */
99
857d50e5 100 ppdSetConformance(PPD_CONFORM_STRICT);
101
4b0b2cf9 102 verbose = 0;
103 ppd = NULL;
1391e7cb 104 files = 0;
4b0b2cf9 105 status = ERROR_NONE;
106
107 for (i = 1; i < argc; i ++)
f249be22 108 if (argv[i][0] == '-' && argv[i][1])
77f83108 109 {
f249be22 110 for (opt = argv[i] + 1; *opt; opt ++)
111 switch (*opt)
112 {
857d50e5 113 case 'q' : /* Quiet mode */
f249be22 114 if (verbose > 0)
115 {
116 fputs("cupstestppd: The -q option is incompatible with the -v option.\n",
117 stderr);
118 return (1);
119 }
77f83108 120
f249be22 121 verbose --;
122 break;
77f83108 123
857d50e5 124 case 'r' : /* Relaxed mode */
125 ppdSetConformance(PPD_CONFORM_RELAXED);
126 break;
127
128 case 'v' : /* Verbose mode */
f249be22 129 if (verbose < 0)
130 {
131 fputs("cupstestppd: The -v option is incompatible with the -q option.\n",
132 stderr);
133 return (1);
134 }
135
136 verbose ++;
137 break;
138
139 default :
140 usage();
141 break;
142 }
4b0b2cf9 143 }
144 else
145 {
146 /*
147 * Open the PPD file...
148 */
149
e7848a5b 150 if (files && verbose >= 0)
5f7c946a 151 putchar('\n');
152
1391e7cb 153 files ++;
154
4b0b2cf9 155 if (argv[i][0] == '-')
156 {
157 /*
158 * Read from stdin...
159 */
160
77f83108 161 if (verbose >= 0)
f249be22 162 printf("(stdin):");
4b0b2cf9 163
164 ppd = ppdOpen(stdin);
165 }
f249be22 166 else if (strlen(argv[i]) > 3 &&
167 !strcmp(argv[i] + strlen(argv[i]) - 3, ".gz"))
168 {
169 /*
170 * Read from a gzipped file...
171 */
172
173 char command[1024]; /* Command string */
174 FILE *gunzip; /* Pipe file */
175
176
177 if (verbose >= 0)
178 printf("%s:", argv[i]);
179
ad10470c 180 snprintf(command, sizeof(command), "gunzip -c \"%s\"", argv[i]);
f249be22 181 gunzip = popen(command, "r");
182 ppd = ppdOpen(gunzip);
183
184 if (gunzip != NULL)
185 pclose(gunzip);
186 }
4b0b2cf9 187 else
188 {
189 /*
190 * Read from a file...
191 */
192
77f83108 193 if (verbose >= 0)
f249be22 194 printf("%s:", argv[i]);
4b0b2cf9 195
196 ppd = ppdOpenFile(argv[i]);
197 }
198
199 if (ppd == NULL)
200 {
1391e7cb 201 error = ppdLastError(&line);
202
8b952de6 203 if (verbose >= 0)
204 printf(" FAIL\n **FAIL** Unable to open PPD file - ");
f69d5f26 205
621b77a6 206 if (error <= PPD_ALLOC_ERROR)
4b0b2cf9 207 {
208 status = ERROR_FILE_OPEN;
77f83108 209
5f7c946a 210 if (verbose >= 0)
f69d5f26 211 puts(strerror(errno));
4b0b2cf9 212 }
213 else
214 {
215 status = ERROR_PPD_FORMAT;
77f83108 216
5f7c946a 217 if (verbose >= 0)
218 {
f69d5f26 219 printf("%s on line %d.\n", ppdErrorString(error), line);
5f7c946a 220
221 switch (error)
222 {
223 case PPD_MISSING_PPDADOBE4 :
8e524f97 224 puts(" REF: Page 42, section 5.2.");
5f7c946a 225 break;
226 case PPD_MISSING_VALUE :
8e524f97 227 puts(" REF: Page 20, section 3.4.");
5f7c946a 228 break;
229 case PPD_BAD_OPEN_GROUP :
230 case PPD_NESTED_OPEN_GROUP :
8e524f97 231 puts(" REF: Pages 45-46, section 5.2.");
5f7c946a 232 break;
233 case PPD_BAD_OPEN_UI :
234 case PPD_NESTED_OPEN_UI :
8e524f97 235 puts(" REF: Pages 42-45, section 5.2.");
5f7c946a 236 break;
237 case PPD_BAD_ORDER_DEPENDENCY :
8e524f97 238 puts(" REF: Pages 48-49, section 5.2.");
5f7c946a 239 break;
240 case PPD_BAD_UI_CONSTRAINTS :
8e524f97 241 puts(" REF: Pages 52-54, section 5.2.");
5f7c946a 242 break;
243 case PPD_MISSING_ASTERISK :
8e524f97 244 puts(" REF: Page 15, section 3.2.");
5f7c946a 245 break;
246 case PPD_LINE_TOO_LONG :
8e524f97 247 puts(" REF: Page 15, section 3.1.");
5f7c946a 248 break;
249 case PPD_ILLEGAL_CHARACTER :
8e524f97 250 puts(" REF: Page 15, section 3.1.");
5f7c946a 251 break;
252 case PPD_ILLEGAL_MAIN_KEYWORD :
8e524f97 253 puts(" REF: Pages 16-17, section 3.2.");
5f7c946a 254 break;
255 case PPD_ILLEGAL_OPTION_KEYWORD :
8e524f97 256 puts(" REF: Page 19, section 3.3.");
5f7c946a 257 break;
258 case PPD_ILLEGAL_TRANSLATION :
8e524f97 259 puts(" REF: Page 27, section 3.5.");
5f7c946a 260 break;
261 default :
262 break;
263 }
264 }
4b0b2cf9 265 }
266
267 continue;
268 }
269
270 /*
271 * Show the header and then perform basic conformance tests (limited
272 * only by what the CUPS PPD functions actually load...)
273 */
274
f9d01894 275 errors = 0;
276 ppdversion = 43;
5f7c946a 277
278 if (verbose > 0)
279 puts("\n DETAILED CONFORMANCE TEST RESULTS");
280
f0e7bfbd 281 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
282 attr->value)
283 ppdversion = (int)(10 * atof(attr->value) + 0.5);
f9d01894 284
99ccff7e 285 if (verbose > 0)
286 {
287 /*
288 * Look for default keywords with no matching option...
289 */
290
291 for (i = 0; i < ppd->num_attrs; i ++)
292 {
293 attr = ppd->attrs[i];
294
295 if (!strcmp(attr->name, "DefaultColorSpace") ||
296 !strcmp(attr->name, "DefaultFont") ||
297 !strcmp(attr->name, "DefaultImageableArea") ||
298 !strcmp(attr->name, "DefaultOutputOrder") ||
299 !strcmp(attr->name, "DefaultPaperDimension") ||
300 !strcmp(attr->name, "DefaultTransfer"))
301 continue;
302
303 if (!strncmp(attr->name, "Default", 7) &&
304 !ppdFindOption(ppd, attr->name + 7))
305 printf(" WARN %s has no corresponding options!\n",
306 attr->name);
307 }
308 }
309
e43abe8b 310 if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
f249be22 311 {
5f7c946a 312 if (verbose >= 0)
313 {
314 if (!errors && !verbose)
315 puts(" FAIL");
f249be22 316
f249be22 317 puts(" **FAIL** REQUIRED DefaultImageableArea");
5f7c946a 318 puts(" REF: Page 102, section 5.15.");
319 }
320
321 errors ++;
f249be22 322 }
e43abe8b 323 else if (ppdPageSize(ppd, attr->value) == NULL)
324 {
325 if (verbose >= 0)
326 {
327 if (!errors && !verbose)
328 puts(" FAIL");
f249be22 329
e43abe8b 330 printf(" **FAIL** BAD DefaultImageableArea %s!\n", attr->value);
331 puts(" REF: Page 102, section 5.15.");
332 }
333
334 errors ++;
335 }
336 else
f249be22 337 {
338 if (verbose > 0)
e43abe8b 339 puts(" PASS DefaultImageableArea");
f249be22 340 }
e43abe8b 341
342 if (ppdFindAttr(ppd, "DefaultPaperDimension", NULL) == NULL)
f249be22 343 {
5f7c946a 344 if (verbose >= 0)
345 {
346 if (!errors && !verbose)
347 puts(" FAIL");
f249be22 348
f249be22 349 puts(" **FAIL** REQUIRED DefaultPaperDimension");
5f7c946a 350 puts(" REF: Page 103, section 5.15.");
351 }
352
353 errors ++;
f249be22 354 }
e43abe8b 355 else if (ppdPageSize(ppd, attr->value) == NULL)
356 {
357 if (verbose >= 0)
358 {
359 if (!errors && !verbose)
360 puts(" FAIL");
361
362 printf(" **FAIL** BAD DefaultPaperDimension %s!\n", attr->value);
363 puts(" REF: Page 103, section 5.15.");
364 }
365
366 errors ++;
367 }
368 else if (verbose > 0)
369 puts(" PASS DefaultPaperDimension");
f249be22 370
4b0b2cf9 371 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
372 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
5c61431a 373 {
374 /*
375 * Verify that we have a default choice...
376 */
377
4b0b2cf9 378 if (option->defchoice[0])
379 {
6bd87d89 380 if (ppdFindChoice(option, option->defchoice) == NULL &&
381 strcmp(option->defchoice, "Unknown"))
e43abe8b 382 {
383 if (verbose >= 0)
384 {
385 if (!errors && !verbose)
386 puts(" FAIL");
387
388 printf(" **FAIL** BAD Default%s %s\n", option->keyword,
389 option->defchoice);
390 puts(" REF: Page 40, section 4.5.");
391 }
392
393 errors ++;
394 }
395 else if (verbose > 0)
77f83108 396 printf(" PASS Default%s\n", option->keyword);
4b0b2cf9 397 }
398 else
399 {
5f7c946a 400 if (verbose >= 0)
401 {
402 if (!errors && !verbose)
403 puts(" FAIL");
77f83108 404
77f83108 405 printf(" **FAIL** REQUIRED Default%s\n", option->keyword);
5f7c946a 406 puts(" REF: Page 40, section 4.5.");
407 }
408
409 errors ++;
4b0b2cf9 410 }
5c61431a 411 }
412
f249be22 413 if (ppdFindAttr(ppd, "FileVersion", NULL) != NULL)
77f83108 414 {
f249be22 415 if (verbose > 0)
416 puts(" PASS FileVersion");
77f83108 417 }
4b0b2cf9 418 else
419 {
5f7c946a 420 if (verbose >= 0)
421 {
422 if (!errors && !verbose)
423 puts(" FAIL");
77f83108 424
f249be22 425 puts(" **FAIL** REQUIRED FileVersion");
5f7c946a 426 puts(" REF: Page 56, section 5.3.");
427 }
428
429 errors ++;
f249be22 430 }
431
432 if (ppdFindAttr(ppd, "FormatVersion", NULL) != NULL)
433 {
434 if (verbose > 0)
435 puts(" PASS FormatVersion");
436 }
437 else
438 {
5f7c946a 439 if (verbose >= 0)
440 {
441 if (!errors && !verbose)
442 puts(" FAIL");
f249be22 443
f249be22 444 puts(" **FAIL** REQUIRED FormatVersion");
5f7c946a 445 puts(" REF: Page 56, section 5.3.");
446 }
447
448 errors ++;
4b0b2cf9 449 }
450
451 if (ppd->lang_encoding != NULL)
77f83108 452 {
f249be22 453 if (verbose > 0)
77f83108 454 puts(" PASS LanguageEncoding");
455 }
5f7c946a 456 else if (ppdversion > 40)
4b0b2cf9 457 {
5f7c946a 458 if (verbose >= 0)
459 {
460 if (!errors && !verbose)
461 puts(" FAIL");
77f83108 462
77f83108 463 puts(" **FAIL** REQUIRED LanguageEncoding");
5f7c946a 464 puts(" REF: Pages 56-57, section 5.3.");
465 }
466
467 errors ++;
4b0b2cf9 468 }
469
470 if (ppd->lang_version != NULL)
77f83108 471 {
f249be22 472 if (verbose > 0)
77f83108 473 puts(" PASS LanguageVersion");
474 }
4b0b2cf9 475 else
476 {
5f7c946a 477 if (verbose >= 0)
478 {
479 if (!errors && !verbose)
480 puts(" FAIL");
77f83108 481
77f83108 482 puts(" **FAIL** REQUIRED LanguageVersion");
5f7c946a 483 puts(" REF: Pages 57-58, section 5.3.");
484 }
485
486 errors ++;
4b0b2cf9 487 }
488
489 if (ppd->manufacturer != NULL)
77f83108 490 {
5acae611 491 if (!strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) ||
492 !strncasecmp(ppd->manufacturer, "Hewlett Packard", 15))
493 {
494 if (verbose >= 0)
495 {
496 if (!errors && !verbose)
497 puts(" FAIL");
498
499 puts(" **FAIL** BAD Manufacturer (should be \"HP\")");
500 puts(" REF: Page 211, table D.1.");
501 }
502
503 errors ++;
504 }
505 else if (verbose > 0)
77f83108 506 puts(" PASS Manufacturer");
507 }
5f7c946a 508 else if (ppdversion >= 43)
4b0b2cf9 509 {
5f7c946a 510 if (verbose >= 0)
511 {
512 if (!errors && !verbose)
513 puts(" FAIL");
77f83108 514
77f83108 515 puts(" **FAIL** REQUIRED Manufacturer");
5f7c946a 516 puts(" REF: Pages 58-59, section 5.3.");
517 }
518
519 errors ++;
4b0b2cf9 520 }
521
522 if (ppd->modelname != NULL)
77f83108 523 {
f249be22 524 for (ptr = ppd->modelname; *ptr; ptr ++)
d3ed5f13 525 if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr))
f249be22 526 break;
527
528 if (*ptr)
529 {
5f7c946a 530 if (verbose >= 0)
531 {
532 if (!errors && !verbose)
533 puts(" FAIL");
f249be22 534
5f7c946a 535 printf(" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n",
536 *ptr);
537 puts(" REF: Pages 59-60, section 5.3.");
538 }
539
540 errors ++;
f249be22 541 }
542 else if (verbose > 0)
77f83108 543 puts(" PASS ModelName");
544 }
4b0b2cf9 545 else
546 {
5f7c946a 547 if (verbose >= 0)
548 {
549 if (!errors && !verbose)
550 puts(" FAIL");
77f83108 551
77f83108 552 puts(" **FAIL** REQUIRED ModelName");
5f7c946a 553 puts(" REF: Pages 59-60, section 5.3.");
554 }
555
556 errors ++;
4b0b2cf9 557 }
558
559 if (ppd->nickname != NULL)
77f83108 560 {
f249be22 561 if (verbose > 0)
77f83108 562 puts(" PASS NickName");
563 }
4b0b2cf9 564 else
565 {
5f7c946a 566 if (verbose >= 0)
567 {
568 if (!errors && !verbose)
569 puts(" FAIL");
77f83108 570
77f83108 571 puts(" **FAIL** REQUIRED NickName");
5f7c946a 572 puts(" REF: Page 60, section 5.3.");
573 }
574
575 errors ++;
4b0b2cf9 576 }
577
578 if (ppdFindOption(ppd, "PageSize") != NULL)
77f83108 579 {
f249be22 580 if (verbose > 0)
77f83108 581 puts(" PASS PageSize");
582 }
4b0b2cf9 583 else
584 {
5f7c946a 585 if (verbose >= 0)
586 {
587 if (!errors && !verbose)
588 puts(" FAIL");
77f83108 589
77f83108 590 puts(" **FAIL** REQUIRED PageSize");
5f7c946a 591 puts(" REF: Pages 99-100, section 5.14.");
592 }
593
594 errors ++;
4b0b2cf9 595 }
596
597 if (ppdFindOption(ppd, "PageRegion") != NULL)
77f83108 598 {
f249be22 599 if (verbose > 0)
77f83108 600 puts(" PASS PageRegion");
601 }
4b0b2cf9 602 else
603 {
5f7c946a 604 if (verbose >= 0)
605 {
606 if (!errors && !verbose)
607 puts(" FAIL");
77f83108 608
77f83108 609 puts(" **FAIL** REQUIRED PageRegion");
5f7c946a 610 puts(" REF: Page 100, section 5.14.");
611 }
612
613 errors ++;
4b0b2cf9 614 }
615
23f5e659 616 if (ppd->pcfilename != NULL)
617 {
f249be22 618 if (verbose > 0)
5f7c946a 619 puts(" PASS PCFileName");
23f5e659 620 }
621 else
622 {
5f7c946a 623 if (verbose >= 0)
624 {
625 if (!errors && !verbose)
626 puts(" FAIL");
23f5e659 627
23f5e659 628 puts(" **FAIL** REQUIRED PCFileName");
5f7c946a 629 puts(" REF: Pages 61-62, section 5.3.");
630 }
631
632 errors ++;
23f5e659 633 }
634
4b0b2cf9 635 if (ppd->product != NULL)
77f83108 636 {
f249be22 637 if (ppd->product[0] != '(' ||
638 ppd->product[strlen(ppd->product) - 1] != ')')
639 {
5f7c946a 640 if (verbose >= 0)
641 {
642 if (!errors && !verbose)
643 puts(" FAIL");
644
645 puts(" **FAIL** BAD Product - not \"(string)\".");
646 puts(" REF: Page 62, section 5.3.");
647 }
f249be22 648
5f7c946a 649 errors ++;
f249be22 650 }
651 else if (verbose > 0)
77f83108 652 puts(" PASS Product");
653 }
4b0b2cf9 654 else
655 {
5f7c946a 656 if (verbose >= 0)
657 {
658 if (!errors && !verbose)
659 puts(" FAIL");
77f83108 660
77f83108 661 puts(" **FAIL** REQUIRED Product");
5f7c946a 662 puts(" REF: Page 62, section 5.3.");
663 }
664
665 errors ++;
4b0b2cf9 666 }
667
f0e7bfbd 668 if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL &&
669 attr->value != NULL)
f249be22 670 {
671 char junkstr[255]; /* Temp string */
672 int junkint; /* Temp integer */
673
674
f0e7bfbd 675 if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2)
f249be22 676 {
5f7c946a 677 if (verbose >= 0)
678 {
679 if (!errors && !verbose)
680 puts(" FAIL");
681
682 puts(" **FAIL** BAD PSVersion - not \"(string) int\".");
683 puts(" REF: Pages 62-64, section 5.3.");
684 }
f249be22 685
5f7c946a 686 errors ++;
f249be22 687 }
688 else if (verbose > 0)
689 puts(" PASS PSVersion");
690 }
691 else
692 {
5f7c946a 693 if (verbose >= 0)
694 {
695 if (!errors && !verbose)
696 puts(" FAIL");
f249be22 697
f249be22 698 puts(" **FAIL** REQUIRED PSVersion");
5f7c946a 699 puts(" REF: Pages 62-64, section 5.3.");
700 }
701
702 errors ++;
f249be22 703 }
704
4b0b2cf9 705 if (ppd->shortnickname != NULL)
77f83108 706 {
f249be22 707 if (strlen(ppd->shortnickname) > 31)
708 {
5f7c946a 709 if (verbose >= 0)
710 {
711 if (!errors && !verbose)
712 puts(" FAIL");
713
714 puts(" **FAIL** BAD ShortNickName - longer than 31 chars.");
715 puts(" REF: Pages 64-65, section 5.3.");
716 }
f249be22 717
5f7c946a 718 errors ++;
f249be22 719 }
720 else if (verbose > 0)
77f83108 721 puts(" PASS ShortNickName");
722 }
5f7c946a 723 else if (ppdversion >= 43)
f9d01894 724 {
5f7c946a 725 if (verbose >= 0)
726 {
727 if (!errors && !verbose)
728 puts(" FAIL");
77f83108 729
77f83108 730 puts(" **FAIL** REQUIRED ShortNickName");
5f7c946a 731 puts(" REF: Page 64-65, section 5.3.");
732 }
733
734 errors ++;
4b0b2cf9 735 }
736
5acae611 737 if (ppd->patches != NULL && strchr(ppd->patches, '\"') &&
738 strstr(ppd->patches, "*End"))
739 {
740 if (verbose >= 0)
741 {
742 if (!errors && !verbose)
743 puts(" FAIL");
744
745 puts(" **FAIL** BAD JobPatchFile attribute in file");
746 puts(" REF: Page 24, section 3.4.");
747 }
748
749 errors ++;
750 }
751
a82a99de 752 /*
753 * Check for page sizes without the corresponding ImageableArea or
754 * PaperDimension values...
755 */
756
757 if (ppd->num_sizes == 0)
758 {
759 if (verbose >= 0)
760 {
761 if (!errors && !verbose)
762 puts(" FAIL");
763
764 puts(" **FAIL** REQUIRED PageSize");
765 puts(" REF: Page 41, section 5.");
766 puts(" REF: Page 99, section 5.14.");
767 }
768
769 errors ++;
770 }
771 else
772 {
773 for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++)
774 {
775 /*
776 * Don't check custom size...
777 */
778
779 if (!strcmp(size->name, "Custom"))
780 continue;
781
782 /*
783 * Check for ImageableArea...
784 */
785
786 if (size->left == 0.0 && size->bottom == 0.0 &&
787 size->right == 0.0 && size->top == 0.0)
788 {
789 if (verbose >= 0)
790 {
791 if (!errors && !verbose)
792 puts(" FAIL");
793
794 printf(" **FAIL** REQUIRED ImageableArea for PageSize %s\n",
795 size->name);
796 puts(" REF: Page 41, section 5.");
797 puts(" REF: Page 102, section 5.15.");
798 }
799
800 errors ++;
801 }
802
803 /*
804 * Check for PaperDimension...
805 */
806
807 if (size->width == 0.0 && size->length == 0.0)
808 {
809 if (verbose >= 0)
810 {
811 if (!errors && !verbose)
812 puts(" FAIL");
813
814 printf(" **FAIL** REQUIRED PaperDimension for PageSize %s\n",
815 size->name);
816 puts(" REF: Page 41, section 5.");
817 puts(" REF: Page 103, section 5.15.");
818 }
819
820 errors ++;
821 }
822 }
823 }
824
cd15b012 825 /*
826 * Check for a duplex option, and for standard values...
827 */
828
829 if ((option = ppdFindOption(ppd, "Duplex")) == NULL)
830 if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
831 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
832 option = ppdFindOption(ppd, "KD03Duplex");
833
834 if (option != NULL)
835 {
836 if (ppdFindChoice(option, "None") == NULL)
837 {
838 if (verbose >= 0)
839 {
840 if (!errors && !verbose)
841 puts(" FAIL");
842
843 printf(" **FAIL** REQUIRED %s does not define choice None!\n",
844 option->keyword);
845 puts(" REF: Page 122, section 5.17");
846 }
847
848 errors ++;
849 }
850
851 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
852 if (strcmp(choice->choice, "None") &&
853 strcmp(choice->choice, "DuplexNoTumble") &&
854 strcmp(choice->choice, "DuplexTumble") &&
855 strcmp(choice->choice, "SimplexTumble"))
856 {
857 if (verbose >= 0)
858 {
859 if (!errors && !verbose)
860 puts(" FAIL");
861
862 printf(" **FAIL** Bad %s choice %s!\n",
863 option->keyword, choice->choice);
864 puts(" REF: Page 122, section 5.17");
865 }
866
867 errors ++;
868 }
869 }
870
4b0b2cf9 871 if (errors)
5f7c946a 872 status = ERROR_CONFORMANCE;
873 else if (!verbose)
874 puts(" PASS");
875
876 if (verbose >= 0)
4b0b2cf9 877 {
cd15b012 878 if (option &&
879 strcmp(option->keyword, "Duplex") &&
880 strcmp(option->keyword, "JCLDuplex"))
881 {
882 printf(" WARN Duplex option keyword %s should be named Duplex!\n",
883 option->keyword);
884 }
885
eafe419c 886 ppdMarkDefaults(ppd);
887 if (ppdConflicts(ppd))
31e1c01a 888 {
eafe419c 889 puts(" WARN Default choices conflicting!");
890
31e1c01a 891 show_conflicts(ppd);
892 }
893
5f7c946a 894 if (ppdversion < 43)
895 {
f0e7bfbd 896 printf(" WARN Obsolete PPD version %.1f!\n",
897 0.1f * ppdversion);
5f7c946a 898 puts(" REF: Page 42, section 5.2.");
899 }
77f83108 900
6fab737b 901 if (!ppd->lang_encoding && ppdversion < 41)
5f7c946a 902 {
903 puts(" WARN LanguageEncoding required by PPD 4.3 spec.");
904 puts(" REF: Pages 56-57, section 5.3.");
905 }
906
907 if (!ppd->manufacturer && ppdversion < 43)
908 {
909 puts(" WARN Manufacturer required by PPD 4.3 spec.");
910 puts(" REF: Pages 58-59, section 5.3.");
911 }
912
913 /*
914 * Treat a PCFileName attribute longer than 12 characters as
915 * a warning and not a hard error...
916 */
917
918 if (ppd->pcfilename && strlen(ppd->pcfilename) > 12)
919 {
920 puts(" WARN PCFileName longer than 8.3 in violation of PPD spec.");
921 puts(" REF: Pages 61-62, section 5.3.");
922 }
923
924 if (!ppd->shortnickname && ppdversion < 43)
925 {
926 puts(" WARN ShortNickName required by PPD 4.3 spec.");
927 puts(" REF: Pages 64-65, section 5.3.");
928 }
b8f94d24 929
4ccd1593 930 /*
931 * Check the Protocols line and flag PJL + BCP since TBCP is
932 * usually used with PJL...
933 */
934
935 if (ppd->protocols)
936 {
937 if (strstr(ppd->protocols, "PJL") &&
938 strstr(ppd->protocols, "BCP") &&
939 !strstr(ppd->protocols, "TBCP"))
940 {
941 puts(" WARN Protocols contains both PJL and BCP; expected TBCP.");
942 puts(" REF: Pages 78-79, section 5.7.");
943 }
944
945 if (strstr(ppd->protocols, "PJL") &&
946 (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps))
947 {
948 puts(" WARN Protocols contains PJL but JCL attributes are not set.");
949 puts(" REF: Pages 78-79, section 5.7.");
950 }
951 }
952
b8f94d24 953 /*
954 * Check for options with a common prefix, e.g. Duplex and Duplexer,
955 * which are errors according to the spec but won't cause problems
956 * with CUPS specifically...
957 */
958
959 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
960 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
961 {
962 len = strlen(option->keyword);
963
964 for (m = 0, group2 = ppd->groups;
965 m < ppd->num_groups;
966 m ++, group2 ++)
967 for (n = 0, option2 = group2->options;
968 n < group2->num_options;
969 n ++, option2 ++)
970 if (option != option2 &&
971 len < strlen(option2->keyword) &&
972 !strncmp(option->keyword, option2->keyword, len))
973 {
974 printf(" WARN %s shares a common prefix with %s\n",
975 option->keyword, option2->keyword);
976 puts(" REF: Page 15, section 3.2.");
977 }
978 }
4b0b2cf9 979 }
980
f249be22 981 if (verbose > 0)
5f7c946a 982 {
983 if (errors)
984 printf(" %d ERROR%s FOUND\n", errors, errors == 1 ? "" : "S");
985 else
986 puts(" NO ERRORS FOUND");
987 }
988
4b0b2cf9 989
990 /*
991 * Then list the options, if "-v" was provided...
992 */
993
f249be22 994 if (verbose > 1)
4b0b2cf9 995 {
996 puts("");
4b0b2cf9 997 printf(" language_level = %d\n", ppd->language_level);
998 printf(" color_device = %s\n", ppd->color_device ? "TRUE" : "FALSE");
999 printf(" variable_sizes = %s\n", ppd->variable_sizes ? "TRUE" : "FALSE");
1000 printf(" landscape = %d\n", ppd->landscape);
1001
1002 switch (ppd->colorspace)
1003 {
1004 case PPD_CS_CMYK :
1005 puts(" colorspace = PPD_CS_CMYK");
1006 break;
1007 case PPD_CS_CMY :
1008 puts(" colorspace = PPD_CS_CMY");
1009 break;
1010 case PPD_CS_GRAY :
1011 puts(" colorspace = PPD_CS_GRAY");
1012 break;
1013 case PPD_CS_RGB :
1014 puts(" colorspace = PPD_CS_RGB");
1015 break;
1016 default :
1017 puts(" colorspace = <unknown>");
1018 break;
1019 }
1020
1021 printf(" num_emulations = %d\n", ppd->num_emulations);
1022 for (j = 0; j < ppd->num_emulations; j ++)
1023 printf(" emulations[%d] = %s\n", j, ppd->emulations[j].name);
1024
1025 printf(" lang_encoding = %s\n", ppd->lang_encoding);
1026 printf(" lang_version = %s\n", ppd->lang_version);
1027 printf(" modelname = %s\n", ppd->modelname);
1028 printf(" ttrasterizer = %s\n",
1029 ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer);
1030 printf(" manufacturer = %s\n", ppd->manufacturer);
1031 printf(" product = %s\n", ppd->product);
1032 printf(" nickname = %s\n", ppd->nickname);
1033 printf(" shortnickname = %s\n", ppd->shortnickname);
1034 printf(" patches = %d bytes\n",
1035 ppd->patches == NULL ? 0 : (int)strlen(ppd->patches));
1036
1037 printf(" num_groups = %d\n", ppd->num_groups);
1038 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1039 {
1040 printf(" group[%d] = %s\n", j, group->text);
1041
1042 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1043 {
1044 printf(" options[%d] = %s (%s) %s %s %.0f (%d choices)\n", k,
1045 option->keyword, option->text, uis[option->ui],
1046 sections[option->section], option->order,
1047 option->num_choices);
1048
1049 if (strcmp(option->keyword, "PageSize") == 0 ||
1050 strcmp(option->keyword, "PageRegion") == 0)
1051 {
1052 for (m = option->num_choices, choice = option->choices;
1053 m > 0;
1054 m --, choice ++)
1055 {
1056 size = ppdPageSize(ppd, choice->choice);
1057
1058 if (size == NULL)
1059 printf(" %s (%s) = ERROR", choice->choice, choice->text);
1060 else
1061 printf(" %s (%s) = %.2fx%.2fin (%.1f,%.1f,%.1f,%.1f)", choice->choice,
1062 choice->text, size->width / 72.0, size->length / 72.0,
1063 size->left / 72.0, size->bottom / 72.0,
1064 size->right / 72.0, size->top / 72.0);
1065
1066 if (strcmp(option->defchoice, choice->choice) == 0)
1067 puts(" *");
1068 else
1069 putchar('\n');
1070 }
1071 }
1072 else
1073 {
1074 for (m = option->num_choices, choice = option->choices;
1075 m > 0;
1076 m --, choice ++)
1077 {
1078 printf(" %s (%s)", choice->choice, choice->text);
1079
1080 if (strcmp(option->defchoice, choice->choice) == 0)
1081 puts(" *");
1082 else
1083 putchar('\n');
1084 }
1085 }
1086 }
1087 }
1088
1089 printf(" num_profiles = %d\n", ppd->num_profiles);
1090 for (j = 0; j < ppd->num_profiles; j ++)
1091 printf(" profiles[%d] = %s/%s %.3f %.3f [ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1092 j, ppd->profiles[j].resolution, ppd->profiles[j].media_type,
1093 ppd->profiles[j].gamma, ppd->profiles[j].density,
1094 ppd->profiles[j].matrix[0][0], ppd->profiles[j].matrix[0][1],
1095 ppd->profiles[j].matrix[0][2], ppd->profiles[j].matrix[1][0],
1096 ppd->profiles[j].matrix[1][1], ppd->profiles[j].matrix[1][2],
1097 ppd->profiles[j].matrix[2][0], ppd->profiles[j].matrix[2][1],
1098 ppd->profiles[j].matrix[2][2]);
1099
1100 printf(" num_fonts = %d\n", ppd->num_fonts);
1101 for (j = 0; j < ppd->num_fonts; j ++)
1102 printf(" fonts[%d] = %s\n", j, ppd->fonts[j]);
5f31ff31 1103
1104 printf(" num_attrs = %d\n", ppd->num_attrs);
1105 for (j = 0; j < ppd->num_attrs; j ++)
1106 printf(" attrs[%d] = %s %s%s%s: \"%s\"\n", j,
1107 ppd->attrs[j]->name, ppd->attrs[j]->spec,
1108 ppd->attrs[j]->text[0] ? "/" : "", ppd->attrs[j]->text,
1109 ppd->attrs[j]->value ? ppd->attrs[j]->value : "(null)");
4b0b2cf9 1110 }
1111
1112 ppdClose(ppd);
1113 }
1114
f249be22 1115 if (!files)
1116 usage();
1117
1118 return (status);
1119}
1120
1121
31e1c01a 1122/*
1123 * 'show_conflicts()' - Show option conflicts in a PPD file.
1124 */
1125
1126void
1127show_conflicts(ppd_file_t *ppd) /* I - PPD to check */
1128{
1129 int i, j; /* Looping variables */
1130 ppd_const_t *c; /* Current constraint */
1131 ppd_option_t *o1, *o2; /* Options */
1132 ppd_choice_t *c1, *c2; /* Choices */
1133
1134
1135 /*
1136 * Loop through all of the UI constraints and report any options
1137 * that conflict...
1138 */
1139
1140 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
1141 {
1142 /*
1143 * Grab pointers to the first option...
1144 */
1145
1146 o1 = ppdFindOption(ppd, c->option1);
1147
1148 if (o1 == NULL)
1149 continue;
1150 else if (c->choice1[0] != '\0')
1151 {
1152 /*
1153 * This constraint maps to a specific choice.
1154 */
1155
1156 c1 = ppdFindChoice(o1, c->choice1);
1157 }
1158 else
1159 {
1160 /*
1161 * This constraint applies to any choice for this option.
1162 */
1163
1164 for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
1165 if (c1->marked)
1166 break;
1167
1168 if (j == 0 ||
1169 strcasecmp(c1->choice, "None") == 0 ||
1170 strcasecmp(c1->choice, "Off") == 0 ||
1171 strcasecmp(c1->choice, "False") == 0)
1172 c1 = NULL;
1173 }
1174
1175 /*
1176 * Grab pointers to the second option...
1177 */
1178
1179 o2 = ppdFindOption(ppd, c->option2);
1180
1181 if (o2 == NULL)
1182 continue;
1183 else if (c->choice2[0] != '\0')
1184 {
1185 /*
1186 * This constraint maps to a specific choice.
1187 */
1188
1189 c2 = ppdFindChoice(o2, c->choice2);
1190 }
1191 else
1192 {
1193 /*
1194 * This constraint applies to any choice for this option.
1195 */
1196
1197 for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
1198 if (c2->marked)
1199 break;
1200
1201 if (j == 0 ||
1202 strcasecmp(c2->choice, "None") == 0 ||
1203 strcasecmp(c2->choice, "Off") == 0 ||
1204 strcasecmp(c2->choice, "False") == 0)
1205 c2 = NULL;
1206 }
1207
1208 /*
1209 * If both options are marked then there is a conflict...
1210 */
1211
1212 if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
1213 printf(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
1214 " (constraint=\"%s %s %s %s\")\n",
1215 o1->keyword, c1->choice, o2->keyword, c2->choice,
1216 c->option1, c->choice1, c->option2, c->choice2);
1217 }
1218}
1219
1220
f249be22 1221/*
1222 * 'usage()' - Show program usage...
1223 */
1224
1225void
1226usage(void)
1227{
857d50e5 1228 puts("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] [... filenameN.ppd[.gz]]");
1229 puts(" program | cupstestppd [-q] [-r] [-v[v]] -");
4b0b2cf9 1230
f249be22 1231 exit(ERROR_USAGE);
4b0b2cf9 1232}
1233
1234
1235/*
fa27cf64 1236 * End of "$Id: cupstestppd.c,v 1.35 2005/01/03 19:29:59 mike Exp $".
4b0b2cf9 1237 */