]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/cupstestppd.c
Load cups into easysw/current.
[thirdparty/cups.git] / systemv / cupstestppd.c
CommitLineData
ef416fc2 1/*
d09495fa 2 * "$Id: cupstestppd.c 5833 2006-08-16 20:05:58Z mike $"
ef416fc2 3 *
4 * PPD test program for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * PostScript is a trademark of Adobe Systems, Inc.
25 *
26 * This file is subject to the Apple OS-Developed Software exception.
27 *
28 * Contents:
29 *
30 * main() - Main entry for test program.
31 * show_conflicts() - Show option conflicts in a PPD file.
32 * usage() - Show program usage...
33 */
34
35/*
36 * Include necessary headers...
37 */
38
39#include <cups/string.h>
40#include <cups/cups.h>
41#include <cups/i18n.h>
42#include <errno.h>
43#include <stdlib.h>
44
45
46/*
47 * Error codes...
48 */
49
fa73b229 50enum
51{
52 ERROR_NONE = 0,
53 ERROR_USAGE,
54 ERROR_FILE_OPEN,
55 ERROR_PPD_FORMAT,
56 ERROR_CONFORMANCE
57};
58
59
60/*
61 * Line endings...
62 */
63
64enum
65{
66 EOL_NONE = 0,
67 EOL_CR,
68 EOL_LF,
69 EOL_CRLF
70};
ef416fc2 71
72
73/*
74 * Local functions...
75 */
76
fa73b229 77void check_basics(const char *filename);
ef416fc2 78void show_conflicts(ppd_file_t *ppd);
79void usage(void);
80
81
82/*
83 * 'main()' - Main entry for test program.
84 */
85
86int /* O - Exit status */
87main(int argc, /* I - Number of command-line arguments */
88 char *argv[]) /* I - Command-line arguments */
89{
90 int i, j, k, m, n; /* Looping vars */
91 int len; /* Length of option name */
92 char *opt; /* Option character */
93 const char *ptr; /* Pointer into string */
94 int files; /* Number of files */
95 int verbose; /* Want verbose output? */
96 int status; /* Exit status */
97 int errors; /* Number of conformance errors */
98 int ppdversion; /* PPD spec version in PPD file */
99 ppd_status_t error; /* Status of ppdOpen*() */
100 int line; /* Line number for error */
101 int xdpi, /* X resolution */
102 ydpi; /* Y resolution */
103 ppd_file_t *ppd; /* PPD file record */
104 ppd_attr_t *attr; /* PPD attribute */
105 ppd_size_t *size; /* Size record */
106 ppd_group_t *group; /* UI group */
107 ppd_option_t *option; /* Standard UI option */
108 ppd_group_t *group2; /* UI group */
109 ppd_option_t *option2; /* Standard UI option */
110 ppd_choice_t *choice; /* Standard UI option choice */
111 static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
112 static char *sections[] = { "ANY", "DOCUMENT", "EXIT",
113 "JCL", "PAGE", "PROLOG" };
114
115
d09495fa 116 _cupsSetLocale();
117
ef416fc2 118 /*
119 * Display PPD files for each file listed on the command-line...
120 */
121
122 ppdSetConformance(PPD_CONFORM_STRICT);
123
124 verbose = 0;
125 ppd = NULL;
126 files = 0;
127 status = ERROR_NONE;
128
129 for (i = 1; i < argc; i ++)
130 if (argv[i][0] == '-' && argv[i][1])
131 {
132 for (opt = argv[i] + 1; *opt; opt ++)
133 switch (*opt)
134 {
135 case 'q' : /* Quiet mode */
136 if (verbose > 0)
137 {
fa73b229 138 _cupsLangPuts(stderr,
ef416fc2 139 _("cupstestppd: The -q option is incompatible "
140 "with the -v option.\n"));
141 return (1);
142 }
143
144 verbose --;
145 break;
146
147 case 'r' : /* Relaxed mode */
148 ppdSetConformance(PPD_CONFORM_RELAXED);
149 break;
150
151 case 'v' : /* Verbose mode */
152 if (verbose < 0)
153 {
fa73b229 154 _cupsLangPuts(stderr,
ef416fc2 155 _("cupstestppd: The -v option is incompatible "
156 "with the -q option.\n"));
157 return (1);
158 }
159
160 verbose ++;
161 break;
162
163 default :
164 usage();
165 break;
166 }
167 }
168 else
169 {
170 /*
171 * Open the PPD file...
172 */
173
174 if (files && verbose >= 0)
fa73b229 175 _cupsLangPuts(stdout, "\n");
ef416fc2 176
177 files ++;
178
179 if (argv[i][0] == '-')
180 {
181 /*
182 * Read from stdin...
183 */
184
185 if (verbose >= 0)
186 printf("(stdin):");
187
188 ppd = ppdOpen(stdin);
189 }
190 else
191 {
192 /*
193 * Read from a file...
194 */
195
196 if (verbose >= 0)
197 printf("%s:", argv[i]);
198
199 ppd = ppdOpenFile(argv[i]);
200 }
201
202 if (ppd == NULL)
203 {
204 error = ppdLastError(&line);
205
206 if (error <= PPD_ALLOC_ERROR)
207 {
208 status = ERROR_FILE_OPEN;
209
210 if (verbose >= 0)
fa73b229 211 _cupsLangPrintf(stdout,
ef416fc2 212 _(" FAIL\n"
213 " **FAIL** Unable to open PPD file - %s\n"),
214 strerror(errno));
215 }
216 else
217 {
218 status = ERROR_PPD_FORMAT;
219
220 if (verbose >= 0)
221 {
fa73b229 222 _cupsLangPrintf(stdout,
ef416fc2 223 _(" FAIL\n"
224 " **FAIL** Unable to open PPD file - "
225 "%s on line %d.\n"),
226 ppdErrorString(error), line);
227
228 switch (error)
229 {
230 case PPD_MISSING_PPDADOBE4 :
fa73b229 231 _cupsLangPuts(stdout,
ef416fc2 232 _(" REF: Page 42, section 5.2.\n"));
233 break;
234 case PPD_MISSING_VALUE :
fa73b229 235 _cupsLangPuts(stdout,
ef416fc2 236 _(" REF: Page 20, section 3.4.\n"));
237 break;
238 case PPD_BAD_OPEN_GROUP :
239 case PPD_NESTED_OPEN_GROUP :
fa73b229 240 _cupsLangPuts(stdout,
ef416fc2 241 _(" REF: Pages 45-46, section 5.2.\n"));
242 break;
243 case PPD_BAD_OPEN_UI :
244 case PPD_NESTED_OPEN_UI :
fa73b229 245 _cupsLangPuts(stdout,
ef416fc2 246 _(" REF: Pages 42-45, section 5.2.\n"));
247 break;
248 case PPD_BAD_ORDER_DEPENDENCY :
fa73b229 249 _cupsLangPuts(stdout,
ef416fc2 250 _(" REF: Pages 48-49, section 5.2.\n"));
251 break;
252 case PPD_BAD_UI_CONSTRAINTS :
fa73b229 253 _cupsLangPuts(stdout,
ef416fc2 254 _(" REF: Pages 52-54, section 5.2.\n"));
255 break;
256 case PPD_MISSING_ASTERISK :
fa73b229 257 _cupsLangPuts(stdout,
ef416fc2 258 _(" REF: Page 15, section 3.2.\n"));
259 break;
260 case PPD_LINE_TOO_LONG :
fa73b229 261 _cupsLangPuts(stdout,
ef416fc2 262 _(" REF: Page 15, section 3.1.\n"));
263 break;
264 case PPD_ILLEGAL_CHARACTER :
fa73b229 265 _cupsLangPuts(stdout,
ef416fc2 266 _(" REF: Page 15, section 3.1.\n"));
267 break;
268 case PPD_ILLEGAL_MAIN_KEYWORD :
fa73b229 269 _cupsLangPuts(stdout,
ef416fc2 270 _(" REF: Pages 16-17, section 3.2.\n"));
271 break;
272 case PPD_ILLEGAL_OPTION_KEYWORD :
fa73b229 273 _cupsLangPuts(stdout,
ef416fc2 274 _(" REF: Page 19, section 3.3.\n"));
275 break;
276 case PPD_ILLEGAL_TRANSLATION :
fa73b229 277 _cupsLangPuts(stdout,
ef416fc2 278 _(" REF: Page 27, section 3.5.\n"));
279 break;
280 default :
281 break;
282 }
fa73b229 283
284 check_basics(argv[i]);
ef416fc2 285 }
286 }
287
288 continue;
289 }
290
291 /*
292 * Show the header and then perform basic conformance tests (limited
293 * only by what the CUPS PPD functions actually load...)
294 */
295
296 errors = 0;
297 ppdversion = 43;
298
299 if (verbose > 0)
fa73b229 300 _cupsLangPuts(stdout,
ef416fc2 301 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
302
303 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
304 attr->value)
305 ppdversion = (int)(10 * atof(attr->value) + 0.5);
306
b423cd4c 307 /*
308 * Look for default keywords with no matching option...
309 */
310
d09495fa 311 for (j = 0; j < ppd->num_attrs; j ++)
ef416fc2 312 {
d09495fa 313 attr = ppd->attrs[j];
ef416fc2 314
b423cd4c 315 if (!strcmp(attr->name, "DefaultColorSpace") ||
316 !strcmp(attr->name, "DefaultFont") ||
317 !strcmp(attr->name, "DefaultImageableArea") ||
318 !strcmp(attr->name, "DefaultOutputOrder") ||
319 !strcmp(attr->name, "DefaultPaperDimension") ||
320 !strcmp(attr->name, "DefaultTransfer"))
321 continue;
322
323 if (!strncmp(attr->name, "Default", 7))
ef416fc2 324 {
89d46774 325 if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
326 strcmp(attr->value, "Unknown"))
b423cd4c 327 {
328 /*
329 * Check that the default option value matches a choice...
330 */
331
d09495fa 332 for (k = 0; k < option->num_choices; k ++)
333 if (!strcmp(option->choices[k].choice, attr->value))
b423cd4c 334 break;
335
d09495fa 336 if (k >= option->num_choices)
b423cd4c 337 {
338 if (verbose >= 0)
339 {
340 if (!errors && !verbose)
341 _cupsLangPuts(stdout, _(" FAIL\n"));
342
343 _cupsLangPrintf(stdout,
344 _(" **FAIL** %s %s does not exist!\n"),
345 attr->name, attr->value);
346 }
347
348 errors ++;
349 }
350 }
351 }
ef416fc2 352 }
353
354 if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
355 {
356 if (verbose >= 0)
357 {
358 if (!errors && !verbose)
fa73b229 359 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 360
fa73b229 361 _cupsLangPuts(stdout,
ef416fc2 362 _(" **FAIL** REQUIRED DefaultImageableArea\n"
363 " REF: Page 102, section 5.15.\n"));
364 }
365
366 errors ++;
367 }
368 else if (ppdPageSize(ppd, attr->value) == NULL &&
369 strcmp(attr->value, "Unknown"))
370 {
371 if (verbose >= 0)
372 {
373 if (!errors && !verbose)
fa73b229 374 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 375
fa73b229 376 _cupsLangPrintf(stdout,
ef416fc2 377 _(" **FAIL** BAD DefaultImageableArea %s!\n"
378 " REF: Page 102, section 5.15.\n"),
379 attr->value);
380 }
381
382 errors ++;
383 }
384 else
385 {
386 if (verbose > 0)
fa73b229 387 _cupsLangPuts(stdout, _(" PASS DefaultImageableArea\n"));
ef416fc2 388 }
389
390 if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL)
391 {
392 if (verbose >= 0)
393 {
394 if (!errors && !verbose)
fa73b229 395 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 396
fa73b229 397 _cupsLangPuts(stdout,
ef416fc2 398 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
399 " REF: Page 103, section 5.15.\n"));
400 }
401
402 errors ++;
403 }
404 else if (ppdPageSize(ppd, attr->value) == NULL &&
405 strcmp(attr->value, "Unknown"))
406 {
407 if (verbose >= 0)
408 {
409 if (!errors && !verbose)
fa73b229 410 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 411
fa73b229 412 _cupsLangPrintf(stdout,
ef416fc2 413 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
414 " REF: Page 103, section 5.15.\n"),
415 attr->value);
416 }
417
418 errors ++;
419 }
420 else if (verbose > 0)
fa73b229 421 _cupsLangPuts(stdout, _(" PASS DefaultPaperDimension\n"));
ef416fc2 422
423 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
424 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
425 {
426 /*
427 * Verify that we have a default choice...
428 */
429
430 if (option->defchoice[0])
431 {
432 if (ppdFindChoice(option, option->defchoice) == NULL &&
433 strcmp(option->defchoice, "Unknown"))
434 {
435 if (verbose >= 0)
436 {
437 if (!errors && !verbose)
fa73b229 438 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 439
fa73b229 440 _cupsLangPrintf(stdout,
ef416fc2 441 _(" **FAIL** BAD Default%s %s\n"
442 " REF: Page 40, section 4.5.\n"),
443 option->keyword, option->defchoice);
444 }
445
446 errors ++;
447 }
448 else if (verbose > 0)
fa73b229 449 _cupsLangPrintf(stdout,
ef416fc2 450 _(" PASS Default%s\n"),
451 option->keyword);
452 }
453 else
454 {
455 if (verbose >= 0)
456 {
457 if (!errors && !verbose)
fa73b229 458 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 459
fa73b229 460 _cupsLangPrintf(stdout,
ef416fc2 461 _(" **FAIL** REQUIRED Default%s\n"
462 " REF: Page 40, section 4.5.\n"),
463 option->keyword);
464 }
465
466 errors ++;
467 }
468 }
469
470 if (ppdFindAttr(ppd, "FileVersion", NULL) != NULL)
471 {
472 if (verbose > 0)
fa73b229 473 _cupsLangPuts(stdout, _(" PASS FileVersion\n"));
ef416fc2 474 }
475 else
476 {
477 if (verbose >= 0)
478 {
479 if (!errors && !verbose)
fa73b229 480 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 481
fa73b229 482 _cupsLangPuts(stdout,
ef416fc2 483 _(" **FAIL** REQUIRED FileVersion\n"
484 " REF: Page 56, section 5.3.\n"));
485 }
486
487 errors ++;
488 }
489
490 if (ppdFindAttr(ppd, "FormatVersion", NULL) != NULL)
491 {
492 if (verbose > 0)
fa73b229 493 _cupsLangPuts(stdout, _(" PASS FormatVersion\n"));
ef416fc2 494 }
495 else
496 {
497 if (verbose >= 0)
498 {
499 if (!errors && !verbose)
fa73b229 500 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 501
fa73b229 502 _cupsLangPuts(stdout,
ef416fc2 503 _(" **FAIL** REQUIRED FormatVersion\n"
504 " REF: Page 56, section 5.3.\n"));
505 }
506
507 errors ++;
508 }
509
510 if (ppd->lang_encoding != NULL)
511 {
512 if (verbose > 0)
fa73b229 513 _cupsLangPuts(stdout, _(" PASS LanguageEncoding\n"));
ef416fc2 514 }
515 else if (ppdversion > 40)
516 {
517 if (verbose >= 0)
518 {
519 if (!errors && !verbose)
fa73b229 520 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 521
fa73b229 522 _cupsLangPuts(stdout,
ef416fc2 523 _(" **FAIL** REQUIRED LanguageEncoding\n"
524 " REF: Pages 56-57, section 5.3.\n"));
525 }
526
527 errors ++;
528 }
529
530 if (ppd->lang_version != NULL)
531 {
532 if (verbose > 0)
fa73b229 533 _cupsLangPuts(stdout, _(" PASS LanguageVersion\n"));
ef416fc2 534 }
535 else
536 {
537 if (verbose >= 0)
538 {
539 if (!errors && !verbose)
fa73b229 540 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 541
fa73b229 542 _cupsLangPuts(stdout,
ef416fc2 543 _(" **FAIL** REQUIRED LanguageVersion\n"
544 " REF: Pages 57-58, section 5.3.\n"));
545 }
546
547 errors ++;
548 }
549
550 if (ppd->manufacturer != NULL)
551 {
552 if (!strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) ||
553 !strncasecmp(ppd->manufacturer, "Hewlett Packard", 15))
554 {
555 if (verbose >= 0)
556 {
557 if (!errors && !verbose)
fa73b229 558 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 559
fa73b229 560 _cupsLangPuts(stdout,
ef416fc2 561 _(" **FAIL** BAD Manufacturer (should be "
562 "\"HP\")\n"
563 " REF: Page 211, table D.1.\n"));
564 }
565
566 errors ++;
567 }
568 else if (verbose > 0)
fa73b229 569 _cupsLangPuts(stdout, _(" PASS Manufacturer\n"));
ef416fc2 570 }
571 else if (ppdversion >= 43)
572 {
573 if (verbose >= 0)
574 {
575 if (!errors && !verbose)
fa73b229 576 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 577
fa73b229 578 _cupsLangPuts(stdout,
ef416fc2 579 _(" **FAIL** REQUIRED Manufacturer\n"
580 " REF: Pages 58-59, section 5.3.\n"));
581 }
582
583 errors ++;
584 }
585
586 if (ppd->modelname != NULL)
587 {
588 for (ptr = ppd->modelname; *ptr; ptr ++)
589 if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr))
590 break;
591
592 if (*ptr)
593 {
594 if (verbose >= 0)
595 {
596 if (!errors && !verbose)
fa73b229 597 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 598
fa73b229 599 _cupsLangPrintf(stdout,
ef416fc2 600 _(" **FAIL** BAD ModelName - \"%c\" not "
601 "allowed in string.\n"
602 " REF: Pages 59-60, section 5.3.\n"),
603 *ptr);
604 }
605
606 errors ++;
607 }
608 else if (verbose > 0)
fa73b229 609 _cupsLangPuts(stdout, _(" PASS ModelName\n"));
ef416fc2 610 }
611 else
612 {
613 if (verbose >= 0)
614 {
615 if (!errors && !verbose)
fa73b229 616 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 617
fa73b229 618 _cupsLangPuts(stdout,
ef416fc2 619 _(" **FAIL** REQUIRED ModelName\n"
620 " REF: Pages 59-60, section 5.3.\n"));
621 }
622
623 errors ++;
624 }
625
626 if (ppd->nickname != NULL)
627 {
628 if (verbose > 0)
fa73b229 629 _cupsLangPuts(stdout, _(" PASS NickName\n"));
ef416fc2 630 }
631 else
632 {
633 if (verbose >= 0)
634 {
635 if (!errors && !verbose)
fa73b229 636 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 637
fa73b229 638 _cupsLangPuts(stdout,
ef416fc2 639 _(" **FAIL** REQUIRED NickName\n"
640 " REF: Page 60, section 5.3.\n"));
641 }
642
643 errors ++;
644 }
645
646 if (ppdFindOption(ppd, "PageSize") != NULL)
647 {
648 if (verbose > 0)
fa73b229 649 _cupsLangPuts(stdout, _(" PASS PageSize\n"));
ef416fc2 650 }
651 else
652 {
653 if (verbose >= 0)
654 {
655 if (!errors && !verbose)
fa73b229 656 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 657
fa73b229 658 _cupsLangPuts(stdout,
ef416fc2 659 _(" **FAIL** REQUIRED PageSize\n"
660 " REF: Pages 99-100, section 5.14.\n"));
661 }
662
663 errors ++;
664 }
665
666 if (ppdFindOption(ppd, "PageRegion") != NULL)
667 {
668 if (verbose > 0)
fa73b229 669 _cupsLangPuts(stdout, _(" PASS PageRegion\n"));
ef416fc2 670 }
671 else
672 {
673 if (verbose >= 0)
674 {
675 if (!errors && !verbose)
fa73b229 676 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 677
fa73b229 678 _cupsLangPuts(stdout,
ef416fc2 679 _(" **FAIL** REQUIRED PageRegion\n"
680 " REF: Page 100, section 5.14.\n"));
681 }
682
683 errors ++;
684 }
685
686 if (ppd->pcfilename != NULL)
687 {
688 if (verbose > 0)
fa73b229 689 _cupsLangPuts(stdout, _(" PASS PCFileName\n"));
ef416fc2 690 }
691 else
692 {
693 if (verbose >= 0)
694 {
695 if (!errors && !verbose)
fa73b229 696 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 697
fa73b229 698 _cupsLangPuts(stdout,
ef416fc2 699 _(" **FAIL** REQUIRED PCFileName\n"
700 " REF: Pages 61-62, section 5.3.\n"));
701 }
702
703 errors ++;
704 }
705
706 if (ppd->product != NULL)
707 {
708 if (ppd->product[0] != '(' ||
709 ppd->product[strlen(ppd->product) - 1] != ')')
710 {
711 if (verbose >= 0)
712 {
713 if (!errors && !verbose)
fa73b229 714 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 715
fa73b229 716 _cupsLangPuts(stdout,
ef416fc2 717 _(" **FAIL** BAD Product - not \"(string)\".\n"
718 " REF: Page 62, section 5.3.\n"));
719 }
720
721 errors ++;
722 }
723 else if (verbose > 0)
fa73b229 724 _cupsLangPuts(stdout, _(" PASS Product\n"));
ef416fc2 725 }
726 else
727 {
728 if (verbose >= 0)
729 {
730 if (!errors && !verbose)
fa73b229 731 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 732
fa73b229 733 _cupsLangPuts(stdout,
ef416fc2 734 _(" **FAIL** REQUIRED Product\n"
735 " REF: Page 62, section 5.3.\n"));
736 }
737
738 errors ++;
739 }
740
741 if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL &&
742 attr->value != NULL)
743 {
744 char junkstr[255]; /* Temp string */
745 int junkint; /* Temp integer */
746
747
748 if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2)
749 {
750 if (verbose >= 0)
751 {
752 if (!errors && !verbose)
fa73b229 753 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 754
fa73b229 755 _cupsLangPuts(stdout,
ef416fc2 756 _(" **FAIL** BAD PSVersion - not \"(string) "
757 "int\".\n"
758 " REF: Pages 62-64, section 5.3.\n"));
759 }
760
761 errors ++;
762 }
763 else if (verbose > 0)
fa73b229 764 _cupsLangPuts(stdout, _(" PASS PSVersion\n"));
ef416fc2 765 }
766 else
767 {
768 if (verbose >= 0)
769 {
770 if (!errors && !verbose)
fa73b229 771 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 772
fa73b229 773 _cupsLangPuts(stdout,
ef416fc2 774 _(" **FAIL** REQUIRED PSVersion\n"
775 " REF: Pages 62-64, section 5.3.\n"));
776 }
777
778 errors ++;
779 }
780
781 if (ppd->shortnickname != NULL)
782 {
783 if (strlen(ppd->shortnickname) > 31)
784 {
785 if (verbose >= 0)
786 {
787 if (!errors && !verbose)
fa73b229 788 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 789
fa73b229 790 _cupsLangPuts(stdout,
ef416fc2 791 _(" **FAIL** BAD ShortNickName - longer "
792 "than 31 chars.\n"
793 " REF: Pages 64-65, section 5.3.\n"));
794 }
795
796 errors ++;
797 }
798 else if (verbose > 0)
fa73b229 799 _cupsLangPuts(stdout, _(" PASS ShortNickName\n"));
ef416fc2 800 }
801 else if (ppdversion >= 43)
802 {
803 if (verbose >= 0)
804 {
805 if (!errors && !verbose)
fa73b229 806 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 807
fa73b229 808 _cupsLangPuts(stdout,
ef416fc2 809 _(" **FAIL** REQUIRED ShortNickName\n"
810 " REF: Page 64-65, section 5.3.\n"));
811 }
812
813 errors ++;
814 }
815
816 if (ppd->patches != NULL && strchr(ppd->patches, '\"') &&
817 strstr(ppd->patches, "*End"))
818 {
819 if (verbose >= 0)
820 {
821 if (!errors && !verbose)
fa73b229 822 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 823
fa73b229 824 _cupsLangPuts(stdout,
ef416fc2 825 _(" **FAIL** BAD JobPatchFile attribute in file\n"
826 " REF: Page 24, section 3.4.\n"));
827 }
828
829 errors ++;
830 }
831
832 /*
833 * Check for page sizes without the corresponding ImageableArea or
834 * PaperDimension values...
835 */
836
837 if (ppd->num_sizes == 0)
838 {
839 if (verbose >= 0)
840 {
841 if (!errors && !verbose)
fa73b229 842 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 843
fa73b229 844 _cupsLangPuts(stdout,
ef416fc2 845 _(" **FAIL** REQUIRED PageSize\n"
846 " REF: Page 41, section 5.\n"
847 " REF: Page 99, section 5.14.\n"));
848 }
849
850 errors ++;
851 }
852 else
853 {
854 for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++)
855 {
856 /*
857 * Don't check custom size...
858 */
859
860 if (!strcmp(size->name, "Custom"))
861 continue;
862
863 /*
864 * Check for ImageableArea...
865 */
866
867 if (size->left == 0.0 && size->bottom == 0.0 &&
868 size->right == 0.0 && size->top == 0.0)
869 {
870 if (verbose >= 0)
871 {
872 if (!errors && !verbose)
fa73b229 873 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 874
fa73b229 875 _cupsLangPrintf(stdout,
ef416fc2 876 _(" **FAIL** REQUIRED ImageableArea for "
877 "PageSize %s\n"
878 " REF: Page 41, section 5.\n"
879 " REF: Page 102, section 5.15.\n"),
880 size->name);
881 }
882
883 errors ++;
884 }
885
886 /*
887 * Check for PaperDimension...
888 */
889
890 if (size->width == 0.0 && size->length == 0.0)
891 {
892 if (verbose >= 0)
893 {
894 if (!errors && !verbose)
fa73b229 895 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 896
fa73b229 897 _cupsLangPrintf(stdout,
ef416fc2 898 _(" **FAIL** REQUIRED PaperDimension "
899 "for PageSize %s\n"
900 " REF: Page 41, section 5.\n"
901 " REF: Page 103, section 5.15.\n"),
902 size->name);
903 }
904
905 errors ++;
906 }
907 }
908 }
909
910 /*
911 * Check for valid Resolution, JCLResolution, or SetResolution values...
912 */
913
914 if ((option = ppdFindOption(ppd, "Resolution")) == NULL)
915 if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL)
916 option = ppdFindOption(ppd, "SetResolution");
917
918 if (option != NULL)
919 {
920 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
921 {
922 /*
923 * Verify that all resolution options are of the form NNNdpi
924 * or NNNxNNNdpi...
925 */
926
927 xdpi = strtol(choice->choice, (char **)&ptr, 10);
928 if (ptr > choice->choice && xdpi > 0)
929 {
930 if (*ptr == 'x')
931 ydpi = strtol(ptr + 1, (char **)&ptr, 10);
932 else
933 ydpi = xdpi;
934 }
935 else
936 ydpi = xdpi;
937
938 if (xdpi <= 0 || ydpi <= 0 || strcmp(ptr, "dpi"))
939 {
940 if (verbose >= 0)
941 {
942 if (!errors && !verbose)
fa73b229 943 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 944
fa73b229 945 _cupsLangPrintf(stdout,
ef416fc2 946 _(" **FAIL** Bad %s choice %s!\n"
947 " REF: Page 84, section 5.9\n"),
948 option->keyword, choice->choice);
949 }
950
951 errors ++;
952 }
953 }
954 }
955
956 /*
957 * Check for a duplex option, and for standard values...
958 */
959
960 if ((option = ppdFindOption(ppd, "Duplex")) == NULL)
961 if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
962 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
963 option = ppdFindOption(ppd, "KD03Duplex");
964
965 if (option != NULL)
966 {
967 if (ppdFindChoice(option, "None") == NULL)
968 {
969 if (verbose >= 0)
970 {
971 if (!errors && !verbose)
fa73b229 972 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 973
fa73b229 974 _cupsLangPrintf(stdout,
ef416fc2 975 _(" **FAIL** REQUIRED %s does not define "
976 "choice None!\n"
977 " REF: Page 122, section 5.17\n"),
978 option->keyword);
979 }
980
981 errors ++;
982 }
983
984 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
985 if (strcmp(choice->choice, "None") &&
986 strcmp(choice->choice, "DuplexNoTumble") &&
987 strcmp(choice->choice, "DuplexTumble") &&
988 strcmp(choice->choice, "SimplexTumble"))
989 {
990 if (verbose >= 0)
991 {
992 if (!errors && !verbose)
fa73b229 993 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 994
fa73b229 995 _cupsLangPrintf(stdout,
ef416fc2 996 _(" **FAIL** Bad %s choice %s!\n"
997 " REF: Page 122, section 5.17\n"),
998 option->keyword, choice->choice);
999 }
1000
1001 errors ++;
1002 }
1003 }
1004
b423cd4c 1005 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
1006 attr->value)
1007 {
1008 /*
1009 * This file contains localizations, check them...
1010 */
1011
1012 char *languages, /* Copy of attribute value */
1013 *langstart, /* Start of current language */
1014 *langptr, /* Pointer into languages */
d09495fa 1015 keyword[PPD_MAX_NAME], /* Localization keyword */
1016 ckeyword[PPD_MAX_NAME]; /* Custom option keyword */
1017 ppd_coption_t *coption; /* Custom option */
1018 ppd_cparam_t *cparam; /* Custom parameter */
b423cd4c 1019
1020
1021 languages = strdup(attr->value);
1022 for (langptr = languages; *langptr;)
1023 {
1024 /*
1025 * Skip leading whitespace...
1026 */
1027
1028 while (isspace(*langptr & 255))
1029 langptr ++;
1030
1031 if (!*langptr)
1032 break;
1033
1034 /*
1035 * Find the end of this language name...
1036 */
1037
1038 for (langstart = langptr;
1039 *langptr && !isspace(*langptr & 255);
1040 langptr ++);
1041
1042 if (*langptr)
1043 *langptr++ = '\0';
1044
1045 j = strlen(langstart);
1046 if (j != 2 && j != 5)
1047 {
1048 if (verbose >= 0)
1049 {
1050 if (!errors && !verbose)
1051 _cupsLangPuts(stdout, _(" FAIL\n"));
1052
1053 _cupsLangPrintf(stdout,
1054 _(" **FAIL** Bad language \"%s\"!\n"),
1055 langstart);
1056 }
1057
1058 errors ++;
1059 continue;
1060 }
1061
1062 /*
1063 * Loop through all options and choices...
1064 */
1065
1066 for (option = ppdFirstOption(ppd);
1067 option;
1068 option = ppdNextOption(ppd))
1069 {
1070 snprintf(keyword, sizeof(keyword), "%s.Translation", langstart);
1071 if (!ppdFindAttr(ppd, keyword, option->keyword))
1072 {
1073 if (verbose >= 0)
1074 {
1075 if (!errors && !verbose)
1076 _cupsLangPuts(stdout, _(" FAIL\n"));
1077
1078 _cupsLangPrintf(stdout,
1079 _(" **FAIL** Missing \"%s\" translation "
1080 "string for option %s!\n"),
1081 langstart, option->keyword);
1082 }
1083
1084 errors ++;
1085 }
1086
1087 for (ptr = option->text; *ptr; ptr ++)
1088 if (*ptr & 128)
1089 break;
1090
1091 if (*ptr)
1092 {
1093 if (verbose >= 0)
1094 {
1095 if (!errors && !verbose)
1096 _cupsLangPuts(stdout, _(" FAIL\n"));
1097
1098 _cupsLangPrintf(stdout,
1099 _(" **FAIL** Default translation "
1100 "string for option %s contains 8-bit "
1101 "characters!\n"),
1102 option->keyword);
1103 }
1104
1105 errors ++;
1106 }
1107
1108 snprintf(keyword, sizeof(keyword), "%s.%s", langstart,
1109 option->keyword);
1110 for (j = 0; j < option->num_choices; j ++)
1111 {
d09495fa 1112 if (!strcasecmp(option->choices[j].choice, "Custom") &&
1113 (coption = ppdFindCustomOption(ppd,
1114 option->keyword)) != NULL)
1115 {
1116 snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
1117 langstart, option->keyword);
1118
1119 if (!ppdFindAttr(ppd, ckeyword, "True"))
1120 {
1121 if (verbose >= 0)
1122 {
1123 if (!errors && !verbose)
1124 _cupsLangPuts(stdout, _(" FAIL\n"));
1125
1126 _cupsLangPrintf(stdout,
1127 _(" **FAIL** Missing \"%s\" "
1128 "translation string for option %s, "
1129 "choice %s!\n"),
1130 langstart, ckeyword + 1 + strlen(langstart),
1131 "True");
1132 }
1133
1134 errors ++;
1135 }
1136
1137 if (strcasecmp(option->keyword, "PageSize"))
1138 {
1139 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
1140 cparam;
1141 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
1142 {
1143 snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
1144 langstart, option->keyword);
1145 if (!ppdFindAttr(ppd, ckeyword, cparam->name))
1146 {
1147 if (verbose >= 0)
1148 {
1149 if (!errors && !verbose)
1150 _cupsLangPuts(stdout, _(" FAIL\n"));
1151
1152 _cupsLangPrintf(stdout,
1153 _(" **FAIL** Missing \"%s\" "
1154 "translation string for option %s, "
1155 "choice %s!\n"),
1156 langstart,
1157 ckeyword + 1 + strlen(langstart),
1158 cparam->name);
1159 }
1160
1161 errors ++;
1162 }
1163 }
1164 }
1165 }
1166 else if (!ppdFindAttr(ppd, keyword, option->choices[j].choice))
b423cd4c 1167 {
1168 if (verbose >= 0)
1169 {
1170 if (!errors && !verbose)
1171 _cupsLangPuts(stdout, _(" FAIL\n"));
1172
1173 _cupsLangPrintf(stdout,
1174 _(" **FAIL** Missing \"%s\" "
1175 "translation string for option %s, "
1176 "choice %s!\n"),
1177 langstart, option->keyword,
1178 option->choices[j].choice);
1179 }
1180
1181 errors ++;
1182 }
1183
1184 for (ptr = option->choices[j].text; *ptr; ptr ++)
1185 if (*ptr & 128)
1186 break;
1187
1188 if (*ptr)
1189 {
1190 if (verbose >= 0)
1191 {
1192 if (!errors && !verbose)
1193 _cupsLangPuts(stdout, _(" FAIL\n"));
1194
1195 _cupsLangPrintf(stdout,
1196 _(" **FAIL** Default translation "
1197 "string for option %s choice %s contains "
1198 "8-bit characters!\n"),
1199 option->keyword,
1200 option->choices[j].choice);
1201 }
1202
1203 errors ++;
1204 }
1205 }
1206 }
1207 }
1208 }
1209
1210 for (attr = ppdFindAttr(ppd, "cupsFilter", NULL);
1211 attr;
1212 attr = ppdFindNextAttr(ppd, "cupsFilter", NULL))
1213 {
1214 char super[16], /* Filter super type */
1215 type[256], /* Filter type */
1216 program[256]; /* Filter program */
1217 int cost; /* Filter cost */
1218
1219
1220 if (!attr->value ||
1221 sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
1222 program) != 4)
1223 {
1224 if (verbose >= 0)
1225 {
1226 if (!errors && !verbose)
1227 _cupsLangPuts(stdout, _(" FAIL\n"));
1228
1229 _cupsLangPrintf(stdout,
1230 _(" **FAIL** Bad cupsFilter value \"%s\"!\n"),
1231 attr->value ? attr->value : "");
1232 }
1233
1234 errors ++;
1235 }
1236 }
1237
f301802f 1238 if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
1239 strcmp(attr->name, "1284DeviceID"))
89d46774 1240 {
1241 if (verbose >= 0)
1242 {
1243 if (!errors && !verbose)
1244 _cupsLangPuts(stdout, _(" FAIL\n"));
1245
d09495fa 1246 _cupsLangPrintf(stdout,
1247 _(" **FAIL** %s must be 1284DeviceID!\n"
1248 " REF: Page 72, section 5.5\n"),
1249 attr->name);
89d46774 1250 }
1251
1252 errors ++;
1253 }
1254
ef416fc2 1255 if (errors)
1256 status = ERROR_CONFORMANCE;
1257 else if (!verbose)
fa73b229 1258 _cupsLangPuts(stdout, _(" PASS\n"));
ef416fc2 1259
1260 if (verbose >= 0)
1261 {
fa73b229 1262 check_basics(argv[i]);
1263
89d46774 1264 /*
1265 * Look for default keywords with no corresponding option...
1266 */
1267
d09495fa 1268 for (j = 0; j < ppd->num_attrs; j ++)
89d46774 1269 {
d09495fa 1270 attr = ppd->attrs[j];
89d46774 1271
1272 if (!strcmp(attr->name, "DefaultColorSpace") ||
1273 !strcmp(attr->name, "DefaultColorSep") ||
1274 !strcmp(attr->name, "DefaultFont") ||
1275 !strcmp(attr->name, "DefaultImageableArea") ||
1276 !strcmp(attr->name, "DefaultOutputOrder") ||
1277 !strcmp(attr->name, "DefaultPaperDimension") ||
1278 !strcmp(attr->name, "DefaultScreenProc") ||
1279 !strcmp(attr->name, "DefaultTransfer"))
1280 continue;
1281
1282 if (!strncmp(attr->name, "Default", 7) &&
1283 !ppdFindOption(ppd, attr->name + 7))
1284 _cupsLangPrintf(stdout,
1285 _(" WARN %s has no corresponding "
1286 "options!\n"),
1287 attr->name);
1288 }
1289
1290 /*
1291 * Check for old Duplex option names...
1292 */
1293
1294 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
1295 option = ppdFindOption(ppd, "KD03Duplex");
1296
1297 if (option)
ef416fc2 1298 {
fa73b229 1299 _cupsLangPrintf(stdout,
ef416fc2 1300 _(" WARN Duplex option keyword %s "
1301 "should be named Duplex or JCLDuplex!\n"
1302 " REF: Page 122, section 5.17\n"),
1303 option->keyword);
1304 }
1305
1306 ppdMarkDefaults(ppd);
1307 if (ppdConflicts(ppd))
1308 {
fa73b229 1309 _cupsLangPuts(stdout,
ef416fc2 1310 _(" WARN Default choices conflicting!\n"));
1311
1312 show_conflicts(ppd);
1313 }
1314
1315 if (ppdversion < 43)
1316 {
fa73b229 1317 _cupsLangPrintf(stdout,
ef416fc2 1318 _(" WARN Obsolete PPD version %.1f!\n"
1319 " REF: Page 42, section 5.2.\n"),
1320 0.1f * ppdversion);
1321 }
1322
1323 if (!ppd->lang_encoding && ppdversion < 41)
1324 {
fa73b229 1325 _cupsLangPuts(stdout,
ef416fc2 1326 _(" WARN LanguageEncoding required by PPD "
1327 "4.3 spec.\n"
1328 " REF: Pages 56-57, section 5.3.\n"));
1329 }
1330
1331 if (!ppd->manufacturer && ppdversion < 43)
1332 {
fa73b229 1333 _cupsLangPuts(stdout,
ef416fc2 1334 _(" WARN Manufacturer required by PPD "
1335 "4.3 spec.\n"
1336 " REF: Pages 58-59, section 5.3.\n"));
1337 }
1338
1339 /*
1340 * Treat a PCFileName attribute longer than 12 characters as
1341 * a warning and not a hard error...
1342 */
1343
1344 if (ppd->pcfilename && strlen(ppd->pcfilename) > 12)
1345 {
fa73b229 1346 _cupsLangPuts(stdout,
ef416fc2 1347 _(" WARN PCFileName longer than 8.3 in "
1348 "violation of PPD spec.\n"
1349 " REF: Pages 61-62, section 5.3.\n"));
1350 }
1351
1352 if (!ppd->shortnickname && ppdversion < 43)
1353 {
fa73b229 1354 _cupsLangPuts(stdout,
ef416fc2 1355 _(" WARN ShortNickName required by PPD "
1356 "4.3 spec.\n"
1357 " REF: Pages 64-65, section 5.3.\n"));
1358 }
1359
1360 /*
1361 * Check the Protocols line and flag PJL + BCP since TBCP is
1362 * usually used with PJL...
1363 */
1364
1365 if (ppd->protocols)
1366 {
1367 if (strstr(ppd->protocols, "PJL") &&
1368 strstr(ppd->protocols, "BCP") &&
1369 !strstr(ppd->protocols, "TBCP"))
1370 {
fa73b229 1371 _cupsLangPuts(stdout,
ef416fc2 1372 _(" WARN Protocols contains both PJL "
1373 "and BCP; expected TBCP.\n"
1374 " REF: Pages 78-79, section 5.7.\n"));
1375 }
1376
1377 if (strstr(ppd->protocols, "PJL") &&
1378 (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps))
1379 {
fa73b229 1380 _cupsLangPuts(stdout,
ef416fc2 1381 _(" WARN Protocols contains PJL but JCL "
1382 "attributes are not set.\n"
1383 " REF: Pages 78-79, section 5.7.\n"));
1384 }
1385 }
1386
1387 /*
1388 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1389 * which are errors according to the spec but won't cause problems
1390 * with CUPS specifically...
1391 */
1392
1393 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1394 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1395 {
1396 len = strlen(option->keyword);
1397
1398 for (m = 0, group2 = ppd->groups;
1399 m < ppd->num_groups;
1400 m ++, group2 ++)
1401 for (n = 0, option2 = group2->options;
1402 n < group2->num_options;
1403 n ++, option2 ++)
1404 if (option != option2 &&
1405 len < strlen(option2->keyword) &&
1406 !strncmp(option->keyword, option2->keyword, len))
1407 {
fa73b229 1408 _cupsLangPrintf(stdout,
ef416fc2 1409 _(" WARN %s shares a common "
1410 "prefix with %s\n"
1411 " REF: Page 15, section "
1412 "3.2.\n"),
1413 option->keyword, option2->keyword);
1414 }
1415 }
1416 }
1417
1418 if (verbose > 0)
1419 {
1420 if (errors)
fa73b229 1421 _cupsLangPrintf(stdout, _(" %d ERROR%s FOUND\n"),
ef416fc2 1422 errors, errors == 1 ? "" : "S");
1423 else
fa73b229 1424 _cupsLangPuts(stdout, _(" NO ERRORS FOUND\n"));
ef416fc2 1425 }
1426
ef416fc2 1427 /*
1428 * Then list the options, if "-v" was provided...
1429 */
1430
1431 if (verbose > 1)
1432 {
fa73b229 1433 _cupsLangPrintf(stdout,
ef416fc2 1434 "\n"
1435 " language_level = %d\n"
1436 " color_device = %s\n"
1437 " variable_sizes = %s\n"
1438 " landscape = %d\n",
1439 ppd->language_level,
1440 ppd->color_device ? "TRUE" : "FALSE",
1441 ppd->variable_sizes ? "TRUE" : "FALSE",
1442 ppd->landscape);
1443
1444 switch (ppd->colorspace)
1445 {
1446 case PPD_CS_CMYK :
fa73b229 1447 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMYK\n");
ef416fc2 1448 break;
1449 case PPD_CS_CMY :
fa73b229 1450 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMY\n");
ef416fc2 1451 break;
1452 case PPD_CS_GRAY :
fa73b229 1453 _cupsLangPuts(stdout, " colorspace = PPD_CS_GRAY\n");
ef416fc2 1454 break;
1455 case PPD_CS_RGB :
fa73b229 1456 _cupsLangPuts(stdout, " colorspace = PPD_CS_RGB\n");
ef416fc2 1457 break;
1458 default :
fa73b229 1459 _cupsLangPuts(stdout, " colorspace = <unknown>\n");
ef416fc2 1460 break;
1461 }
1462
fa73b229 1463 _cupsLangPrintf(stdout, " num_emulations = %d\n",
ef416fc2 1464 ppd->num_emulations);
1465 for (j = 0; j < ppd->num_emulations; j ++)
fa73b229 1466 _cupsLangPrintf(stdout, " emulations[%d] = %s\n",
ef416fc2 1467 j, ppd->emulations[j].name);
1468
fa73b229 1469 _cupsLangPrintf(stdout, " lang_encoding = %s\n",
ef416fc2 1470 ppd->lang_encoding);
fa73b229 1471 _cupsLangPrintf(stdout, " lang_version = %s\n",
ef416fc2 1472 ppd->lang_version);
fa73b229 1473 _cupsLangPrintf(stdout, " modelname = %s\n", ppd->modelname);
1474 _cupsLangPrintf(stdout, " ttrasterizer = %s\n",
ef416fc2 1475 ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer);
fa73b229 1476 _cupsLangPrintf(stdout, " manufacturer = %s\n",
ef416fc2 1477 ppd->manufacturer);
fa73b229 1478 _cupsLangPrintf(stdout, " product = %s\n", ppd->product);
1479 _cupsLangPrintf(stdout, " nickname = %s\n", ppd->nickname);
1480 _cupsLangPrintf(stdout, " shortnickname = %s\n",
ef416fc2 1481 ppd->shortnickname);
fa73b229 1482 _cupsLangPrintf(stdout, " patches = %d bytes\n",
ef416fc2 1483 ppd->patches == NULL ? 0 : (int)strlen(ppd->patches));
1484
fa73b229 1485 _cupsLangPrintf(stdout, " num_groups = %d\n", ppd->num_groups);
ef416fc2 1486 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1487 {
fa73b229 1488 _cupsLangPrintf(stdout, " group[%d] = %s\n",
ef416fc2 1489 j, group->text);
1490
1491 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1492 {
fa73b229 1493 _cupsLangPrintf(stdout,
ef416fc2 1494 " options[%d] = %s (%s) %s %s %.0f "
1495 "(%d choices)\n",
1496 k, option->keyword, option->text, uis[option->ui],
1497 sections[option->section], option->order,
1498 option->num_choices);
1499
1500 if (!strcmp(option->keyword, "PageSize") ||
1501 !strcmp(option->keyword, "PageRegion"))
1502 {
1503 for (m = option->num_choices, choice = option->choices;
1504 m > 0;
1505 m --, choice ++)
1506 {
1507 size = ppdPageSize(ppd, choice->choice);
1508
1509 if (size == NULL)
fa73b229 1510 _cupsLangPrintf(stdout,
ef416fc2 1511 " %s (%s) = ERROR",
1512 choice->choice, choice->text);
1513 else
fa73b229 1514 _cupsLangPrintf(stdout,
ef416fc2 1515 " %s (%s) = %.2fx%.2fin "
1516 "(%.1f,%.1f,%.1f,%.1f)",
1517 choice->choice, choice->text,
1518 size->width / 72.0, size->length / 72.0,
1519 size->left / 72.0, size->bottom / 72.0,
1520 size->right / 72.0, size->top / 72.0);
1521
1522 if (!strcmp(option->defchoice, choice->choice))
fa73b229 1523 _cupsLangPuts(stdout, " *\n");
ef416fc2 1524 else
fa73b229 1525 _cupsLangPuts(stdout, "\n");
ef416fc2 1526 }
1527 }
1528 else
1529 {
1530 for (m = option->num_choices, choice = option->choices;
1531 m > 0;
1532 m --, choice ++)
1533 {
fa73b229 1534 _cupsLangPrintf(stdout, " %s (%s)",
ef416fc2 1535 choice->choice, choice->text);
1536
1537 if (!strcmp(option->defchoice, choice->choice))
fa73b229 1538 _cupsLangPuts(stdout, " *\n");
ef416fc2 1539 else
fa73b229 1540 _cupsLangPuts(stdout, "\n");
ef416fc2 1541 }
1542 }
1543 }
1544 }
1545
fa73b229 1546 _cupsLangPrintf(stdout, " num_profiles = %d\n",
ef416fc2 1547 ppd->num_profiles);
1548 for (j = 0; j < ppd->num_profiles; j ++)
fa73b229 1549 _cupsLangPrintf(stdout,
ef416fc2 1550 " profiles[%d] = %s/%s %.3f %.3f "
1551 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1552 j, ppd->profiles[j].resolution,
1553 ppd->profiles[j].media_type,
1554 ppd->profiles[j].gamma, ppd->profiles[j].density,
1555 ppd->profiles[j].matrix[0][0],
1556 ppd->profiles[j].matrix[0][1],
1557 ppd->profiles[j].matrix[0][2],
1558 ppd->profiles[j].matrix[1][0],
1559 ppd->profiles[j].matrix[1][1],
1560 ppd->profiles[j].matrix[1][2],
1561 ppd->profiles[j].matrix[2][0],
1562 ppd->profiles[j].matrix[2][1],
1563 ppd->profiles[j].matrix[2][2]);
1564
fa73b229 1565 _cupsLangPrintf(stdout, " num_fonts = %d\n", ppd->num_fonts);
ef416fc2 1566 for (j = 0; j < ppd->num_fonts; j ++)
fa73b229 1567 _cupsLangPrintf(stdout, " fonts[%d] = %s\n",
ef416fc2 1568 j, ppd->fonts[j]);
1569
fa73b229 1570 _cupsLangPrintf(stdout, " num_attrs = %d\n", ppd->num_attrs);
ef416fc2 1571 for (j = 0; j < ppd->num_attrs; j ++)
fa73b229 1572 _cupsLangPrintf(stdout,
ef416fc2 1573 " attrs[%d] = %s %s%s%s: \"%s\"\n", j,
1574 ppd->attrs[j]->name, ppd->attrs[j]->spec,
1575 ppd->attrs[j]->text[0] ? "/" : "",
1576 ppd->attrs[j]->text,
1577 ppd->attrs[j]->value ?
1578 ppd->attrs[j]->value : "(null)");
1579 }
1580
1581 ppdClose(ppd);
1582 }
1583
1584 if (!files)
1585 usage();
1586
1587 return (status);
1588}
1589
1590
fa73b229 1591/*
1592 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1593 */
1594
1595void
1596check_basics(const char *filename) /* I - PPD file to check */
1597{
1598 cups_file_t *fp; /* File pointer */
1599 int ch; /* Current character */
1600 int col, /* Current column */
1601 whitespace; /* Only seen whitespace? */
1602 int eol; /* Line endings */
1603 int linenum; /* Line number */
1604 int mixed; /* Mixed line endings? */
1605
1606
1607 if ((fp = cupsFileOpen(filename, "r")) == NULL)
1608 return;
1609
1610 linenum = 1;
1611 col = 0;
1612 eol = EOL_NONE;
1613 mixed = 0;
1614 whitespace = 1;
1615
1616 while ((ch = cupsFileGetChar(fp)) != EOF)
1617 {
1618 if (ch == '\r' || ch == '\n')
1619 {
1620 if (ch == '\n')
1621 {
1622 if (eol == EOL_NONE)
1623 eol = EOL_LF;
1624 else if (eol != EOL_LF)
1625 mixed = 1;
1626 }
1627 else if (ch == '\r')
1628 {
1629 if (cupsFilePeekChar(fp) == '\n')
1630 {
1631 cupsFileGetChar(fp);
1632
1633 if (eol == EOL_NONE)
1634 eol = EOL_CRLF;
1635 else
1636 mixed = 1;
1637 }
1638 else if (eol == EOL_NONE)
1639 eol = EOL_CR;
1640 else
1641 mixed = 1;
1642 }
1643
1644 if (col > 0 && whitespace)
1645 _cupsLangPrintf(stdout,
1646 _(" WARN Line %d only contains whitespace!\n"),
1647 linenum);
1648
1649 linenum ++;
1650 col = 0;
1651 whitespace = 1;
1652 }
1653 else
1654 {
1655 if (ch != ' ' && ch != '\t')
1656 whitespace = 0;
1657
1658 col ++;
1659 }
1660 }
1661
1662 if (mixed)
1663 _cupsLangPuts(stdout,
1664 _(" WARN File contains a mix of CR, LF, and "
1665 "CR LF line endings!\n"));
1666
1667 if (eol == EOL_CRLF)
1668 _cupsLangPuts(stdout,
1669 _(" WARN Non-Windows PPD files should use lines "
1670 "ending with only LF, not CR LF!\n"));
1671
1672 cupsFileClose(fp);
1673}
1674
1675
ef416fc2 1676/*
1677 * 'show_conflicts()' - Show option conflicts in a PPD file.
1678 */
1679
1680void
1681show_conflicts(ppd_file_t *ppd) /* I - PPD to check */
1682{
1683 int i, j; /* Looping variables */
1684 ppd_const_t *c; /* Current constraint */
1685 ppd_option_t *o1, *o2; /* Options */
1686 ppd_choice_t *c1, *c2; /* Choices */
1687
1688
1689 /*
1690 * Loop through all of the UI constraints and report any options
1691 * that conflict...
1692 */
1693
1694 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
1695 {
1696 /*
1697 * Grab pointers to the first option...
1698 */
1699
1700 o1 = ppdFindOption(ppd, c->option1);
1701
1702 if (o1 == NULL)
1703 continue;
1704 else if (c->choice1[0] != '\0')
1705 {
1706 /*
1707 * This constraint maps to a specific choice.
1708 */
1709
1710 c1 = ppdFindChoice(o1, c->choice1);
1711 }
1712 else
1713 {
1714 /*
1715 * This constraint applies to any choice for this option.
1716 */
1717
1718 for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
1719 if (c1->marked)
1720 break;
1721
1722 if (j == 0 ||
1723 !strcasecmp(c1->choice, "None") ||
1724 !strcasecmp(c1->choice, "Off") ||
1725 !strcasecmp(c1->choice, "False"))
1726 c1 = NULL;
1727 }
1728
1729 /*
1730 * Grab pointers to the second option...
1731 */
1732
1733 o2 = ppdFindOption(ppd, c->option2);
1734
1735 if (o2 == NULL)
1736 continue;
1737 else if (c->choice2[0] != '\0')
1738 {
1739 /*
1740 * This constraint maps to a specific choice.
1741 */
1742
1743 c2 = ppdFindChoice(o2, c->choice2);
1744 }
1745 else
1746 {
1747 /*
1748 * This constraint applies to any choice for this option.
1749 */
1750
1751 for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
1752 if (c2->marked)
1753 break;
1754
1755 if (j == 0 ||
1756 !strcasecmp(c2->choice, "None") ||
1757 !strcasecmp(c2->choice, "Off") ||
1758 !strcasecmp(c2->choice, "False"))
1759 c2 = NULL;
1760 }
1761
1762 /*
1763 * If both options are marked then there is a conflict...
1764 */
1765
1766 if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
fa73b229 1767 _cupsLangPrintf(stdout,
ef416fc2 1768 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
1769 " (constraint=\"%s %s %s %s\")\n"),
1770 o1->keyword, c1->choice, o2->keyword, c2->choice,
1771 c->option1, c->choice1, c->option2, c->choice2);
1772 }
1773}
1774
1775
1776/*
1777 * 'usage()' - Show program usage...
1778 */
1779
1780void
1781usage(void)
1782{
fa73b229 1783 _cupsLangPuts(stdout,
ef416fc2 1784 _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] "
1785 "[... filenameN.ppd[.gz]]\n"
1786 " program | cupstestppd [-q] [-r] [-v[v]] -\n"));
1787
1788 exit(ERROR_USAGE);
1789}
1790
1791
1792/*
d09495fa 1793 * End of "$Id: cupstestppd.c 5833 2006-08-16 20:05:58Z mike $".
ef416fc2 1794 */