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