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