]> 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/*
bc44d920 2 * "$Id: cupstestppd.c 6649 2007-07-11 21:46:42Z mike $"
ef416fc2 3 *
4 * PPD test program for the Common UNIX Printing System (CUPS).
5 *
bc44d920 6 * Copyright 2007 by Apple Inc.
f7deaa1a 7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
9 * These coded instructions, statements, and computer programs are the
bc44d920 10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 *
15 * PostScript is a trademark of Adobe Systems, Inc.
16 *
17 * This file is subject to the Apple OS-Developed Software exception.
18 *
19 * Contents:
20 *
09a101d6 21 * main() - Main entry for test program.
22 * check_basics() - Check for CR LF, mixed line endings, and blank lines.
23 * check_constraints() - Check UIConstraints in the PPD file.
24 * check_defaults() - Check default option keywords in the PPD file.
25 * check_filters() - Check filters in the PPD file.
26 * check_translations() - Check translations in the PPD file.
27 * show_conflicts() - Show option conflicts in a PPD file.
28 * test_raster() - Test PostScript commands for raster printers.
29 * usage() - Show program usage...
30 * valid_utf8() - Check whether a string contains valid UTF-8 text.
ef416fc2 31 */
32
33/*
34 * Include necessary headers...
35 */
36
37#include <cups/string.h>
38#include <cups/cups.h>
39#include <cups/i18n.h>
09a101d6 40#include <filter/raster.h>
ef416fc2 41#include <errno.h>
42#include <stdlib.h>
323c5de1 43#include <sys/stat.h>
ef416fc2 44
45
b94498cf 46/*
47 * Error warning overrides...
48 */
49
50enum
51{
52 WARN_NONE = 0,
53 WARN_CONSTRAINTS = 1,
54 WARN_DEFAULTS = 2,
55 WARN_FILTERS = 4,
56 WARN_TRANSLATIONS = 8,
57 WARN_ALL = 15
58};
59
60
ef416fc2 61/*
62 * Error codes...
63 */
64
fa73b229 65enum
66{
67 ERROR_NONE = 0,
68 ERROR_USAGE,
69 ERROR_FILE_OPEN,
70 ERROR_PPD_FORMAT,
71 ERROR_CONFORMANCE
72};
73
74
75/*
76 * Line endings...
77 */
78
79enum
80{
81 EOL_NONE = 0,
82 EOL_CR,
83 EOL_LF,
84 EOL_CRLF
85};
ef416fc2 86
87
88/*
89 * Local functions...
90 */
91
3d8365b8 92static void check_basics(const char *filename);
93static int check_constraints(ppd_file_t *ppd, int errors, int verbose,
94 int warn);
95static int check_defaults(ppd_file_t *ppd, int errors, int verbose,
96 int warn);
97static int check_filters(ppd_file_t *ppd, const char *root, int errors,
98 int verbose, int warn);
99static int check_translations(ppd_file_t *ppd, int errors, int verbose,\
100 int warn);
101static void show_conflicts(ppd_file_t *ppd);
09a101d6 102static int test_raster(ppd_file_t *ppd, int verbose);
3d8365b8 103static void usage(void);
104static int valid_utf8(const char *s);
ef416fc2 105
b94498cf 106
ef416fc2 107/*
108 * 'main()' - Main entry for test program.
109 */
110
323c5de1 111int /* O - Exit status */
112main(int argc, /* I - Number of command-line args */
113 char *argv[]) /* I - Command-line arguments */
ef416fc2 114{
323c5de1 115 int i, j, k, m, n; /* Looping vars */
116 int len; /* Length of option name */
117 char *opt; /* Option character */
118 const char *ptr; /* Pointer into string */
119 int files; /* Number of files */
120 int verbose; /* Want verbose output? */
b94498cf 121 int warn; /* Which errors to just warn about */
323c5de1 122 int status; /* Exit status */
123 int errors; /* Number of conformance errors */
124 int ppdversion; /* PPD spec version in PPD file */
125 ppd_status_t error; /* Status of ppdOpen*() */
126 int line; /* Line number for error */
127 struct stat statbuf; /* File information */
b94498cf 128 char pathprog[1024], /* Complete path to program/filter */
323c5de1 129 *root; /* Root directory */
323c5de1 130 int xdpi, /* X resolution */
131 ydpi; /* Y resolution */
132 ppd_file_t *ppd; /* PPD file record */
133 ppd_attr_t *attr; /* PPD attribute */
134 ppd_size_t *size; /* Size record */
135 ppd_group_t *group; /* UI group */
136 ppd_option_t *option; /* Standard UI option */
137 ppd_group_t *group2; /* UI group */
138 ppd_option_t *option2; /* Standard UI option */
139 ppd_choice_t *choice; /* Standard UI option choice */
ef416fc2 140 static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
141 static char *sections[] = { "ANY", "DOCUMENT", "EXIT",
142 "JCL", "PAGE", "PROLOG" };
143
144
07725fee 145 _cupsSetLocale(argv);
d09495fa 146
ef416fc2 147 /*
148 * Display PPD files for each file listed on the command-line...
149 */
150
151 ppdSetConformance(PPD_CONFORM_STRICT);
152
153 verbose = 0;
154 ppd = NULL;
155 files = 0;
156 status = ERROR_NONE;
323c5de1 157 root = "";
b94498cf 158 warn = WARN_NONE;
ef416fc2 159
160 for (i = 1; i < argc; i ++)
161 if (argv[i][0] == '-' && argv[i][1])
162 {
163 for (opt = argv[i] + 1; *opt; opt ++)
164 switch (*opt)
165 {
323c5de1 166 case 'R' : /* Alternate root directory */
167 i ++;
168
169 if (i >= argc)
170 usage();
171
172 root = argv[i];
173 break;
174
b94498cf 175 case 'W' : /* Turn errors into warnings */
176 i ++;
177
178 if (i >= argc)
179 usage();
180
181 if (!strcmp(argv[i], "none"))
182 warn = WARN_NONE;
183 else if (!strcmp(argv[i], "constraints"))
184 warn |= WARN_CONSTRAINTS;
185 else if (!strcmp(argv[i], "defaults"))
186 warn |= WARN_DEFAULTS;
187 else if (!strcmp(argv[i], "filters"))
188 warn |= WARN_FILTERS;
189 else if (!strcmp(argv[i], "translations"))
190 warn |= WARN_TRANSLATIONS;
191 else if (!strcmp(argv[i], "all"))
192 warn = WARN_ALL;
193 else
194 usage();
195 break;
196
ef416fc2 197 case 'q' : /* Quiet mode */
198 if (verbose > 0)
199 {
fa73b229 200 _cupsLangPuts(stderr,
ef416fc2 201 _("cupstestppd: The -q option is incompatible "
202 "with the -v option.\n"));
203 return (1);
204 }
205
206 verbose --;
207 break;
208
209 case 'r' : /* Relaxed mode */
210 ppdSetConformance(PPD_CONFORM_RELAXED);
211 break;
212
213 case 'v' : /* Verbose mode */
214 if (verbose < 0)
215 {
fa73b229 216 _cupsLangPuts(stderr,
ef416fc2 217 _("cupstestppd: The -v option is incompatible "
218 "with the -q option.\n"));
219 return (1);
220 }
221
222 verbose ++;
223 break;
224
225 default :
226 usage();
227 break;
228 }
229 }
230 else
231 {
232 /*
233 * Open the PPD file...
234 */
235
236 if (files && verbose >= 0)
fa73b229 237 _cupsLangPuts(stdout, "\n");
ef416fc2 238
239 files ++;
240
241 if (argv[i][0] == '-')
242 {
243 /*
244 * Read from stdin...
245 */
246
247 if (verbose >= 0)
248 printf("(stdin):");
249
250 ppd = ppdOpen(stdin);
251 }
252 else
253 {
254 /*
255 * Read from a file...
256 */
257
258 if (verbose >= 0)
259 printf("%s:", argv[i]);
260
261 ppd = ppdOpenFile(argv[i]);
262 }
263
264 if (ppd == NULL)
265 {
266 error = ppdLastError(&line);
267
268 if (error <= PPD_ALLOC_ERROR)
269 {
270 status = ERROR_FILE_OPEN;
271
272 if (verbose >= 0)
fa73b229 273 _cupsLangPrintf(stdout,
ef416fc2 274 _(" FAIL\n"
275 " **FAIL** Unable to open PPD file - %s\n"),
276 strerror(errno));
277 }
278 else
279 {
280 status = ERROR_PPD_FORMAT;
281
282 if (verbose >= 0)
283 {
fa73b229 284 _cupsLangPrintf(stdout,
ef416fc2 285 _(" FAIL\n"
286 " **FAIL** Unable to open PPD file - "
287 "%s on line %d.\n"),
288 ppdErrorString(error), line);
289
290 switch (error)
291 {
292 case PPD_MISSING_PPDADOBE4 :
fa73b229 293 _cupsLangPuts(stdout,
ef416fc2 294 _(" REF: Page 42, section 5.2.\n"));
295 break;
296 case PPD_MISSING_VALUE :
fa73b229 297 _cupsLangPuts(stdout,
ef416fc2 298 _(" REF: Page 20, section 3.4.\n"));
299 break;
300 case PPD_BAD_OPEN_GROUP :
301 case PPD_NESTED_OPEN_GROUP :
fa73b229 302 _cupsLangPuts(stdout,
ef416fc2 303 _(" REF: Pages 45-46, section 5.2.\n"));
304 break;
305 case PPD_BAD_OPEN_UI :
306 case PPD_NESTED_OPEN_UI :
fa73b229 307 _cupsLangPuts(stdout,
ef416fc2 308 _(" REF: Pages 42-45, section 5.2.\n"));
309 break;
310 case PPD_BAD_ORDER_DEPENDENCY :
fa73b229 311 _cupsLangPuts(stdout,
ef416fc2 312 _(" REF: Pages 48-49, section 5.2.\n"));
313 break;
314 case PPD_BAD_UI_CONSTRAINTS :
fa73b229 315 _cupsLangPuts(stdout,
ef416fc2 316 _(" REF: Pages 52-54, section 5.2.\n"));
317 break;
318 case PPD_MISSING_ASTERISK :
fa73b229 319 _cupsLangPuts(stdout,
ef416fc2 320 _(" REF: Page 15, section 3.2.\n"));
321 break;
322 case PPD_LINE_TOO_LONG :
fa73b229 323 _cupsLangPuts(stdout,
ef416fc2 324 _(" REF: Page 15, section 3.1.\n"));
325 break;
326 case PPD_ILLEGAL_CHARACTER :
fa73b229 327 _cupsLangPuts(stdout,
ef416fc2 328 _(" REF: Page 15, section 3.1.\n"));
329 break;
330 case PPD_ILLEGAL_MAIN_KEYWORD :
fa73b229 331 _cupsLangPuts(stdout,
ef416fc2 332 _(" REF: Pages 16-17, section 3.2.\n"));
333 break;
334 case PPD_ILLEGAL_OPTION_KEYWORD :
fa73b229 335 _cupsLangPuts(stdout,
ef416fc2 336 _(" REF: Page 19, section 3.3.\n"));
337 break;
338 case PPD_ILLEGAL_TRANSLATION :
fa73b229 339 _cupsLangPuts(stdout,
ef416fc2 340 _(" REF: Page 27, section 3.5.\n"));
341 break;
342 default :
343 break;
344 }
fa73b229 345
346 check_basics(argv[i]);
ef416fc2 347 }
348 }
349
350 continue;
351 }
352
353 /*
354 * Show the header and then perform basic conformance tests (limited
355 * only by what the CUPS PPD functions actually load...)
356 */
357
358 errors = 0;
359 ppdversion = 43;
360
361 if (verbose > 0)
fa73b229 362 _cupsLangPuts(stdout,
ef416fc2 363 _("\n DETAILED CONFORMANCE TEST RESULTS\n"));
364
365 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
366 attr->value)
367 ppdversion = (int)(10 * atof(attr->value) + 0.5);
368
09a101d6 369 for (j = 0; j < ppd->num_filters; j ++)
370 if (strstr(ppd->filters[j], "application/vnd.cups-raster"))
371 {
372 if (!test_raster(ppd, verbose))
373 errors ++;
374 break;
375 }
376
b423cd4c 377 /*
378 * Look for default keywords with no matching option...
379 */
380
b94498cf 381 if (!(warn & WARN_DEFAULTS))
382 errors = check_defaults(ppd, errors, verbose, 0);
ef416fc2 383
384 if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
385 {
386 if (verbose >= 0)
387 {
388 if (!errors && !verbose)
fa73b229 389 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 390
fa73b229 391 _cupsLangPuts(stdout,
b94498cf 392 _(" **FAIL** REQUIRED DefaultImageableArea\n"
ef416fc2 393 " REF: Page 102, section 5.15.\n"));
b94498cf 394 }
ef416fc2 395
396 errors ++;
397 }
398 else if (ppdPageSize(ppd, attr->value) == NULL &&
b94498cf 399 strcmp(attr->value, "Unknown"))
ef416fc2 400 {
401 if (verbose >= 0)
402 {
403 if (!errors && !verbose)
fa73b229 404 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 405
fa73b229 406 _cupsLangPrintf(stdout,
b94498cf 407 _(" **FAIL** BAD DefaultImageableArea %s!\n"
ef416fc2 408 " REF: Page 102, section 5.15.\n"),
409 attr->value);
b94498cf 410 }
ef416fc2 411
412 errors ++;
413 }
414 else
415 {
416 if (verbose > 0)
fa73b229 417 _cupsLangPuts(stdout, _(" PASS DefaultImageableArea\n"));
ef416fc2 418 }
419
420 if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL)
421 {
422 if (verbose >= 0)
423 {
424 if (!errors && !verbose)
fa73b229 425 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 426
fa73b229 427 _cupsLangPuts(stdout,
b94498cf 428 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
ef416fc2 429 " REF: Page 103, section 5.15.\n"));
b94498cf 430 }
ef416fc2 431
432 errors ++;
433 }
434 else if (ppdPageSize(ppd, attr->value) == NULL &&
b94498cf 435 strcmp(attr->value, "Unknown"))
ef416fc2 436 {
437 if (verbose >= 0)
438 {
439 if (!errors && !verbose)
fa73b229 440 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 441
fa73b229 442 _cupsLangPrintf(stdout,
b94498cf 443 _(" **FAIL** BAD DefaultPaperDimension %s!\n"
ef416fc2 444 " REF: Page 103, section 5.15.\n"),
445 attr->value);
b94498cf 446 }
ef416fc2 447
448 errors ++;
449 }
450 else if (verbose > 0)
fa73b229 451 _cupsLangPuts(stdout, _(" PASS DefaultPaperDimension\n"));
ef416fc2 452
453 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
454 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
455 {
456 /*
457 * Verify that we have a default choice...
458 */
459
460 if (option->defchoice[0])
461 {
b94498cf 462 if (ppdFindChoice(option, option->defchoice) == NULL &&
463 strcmp(option->defchoice, "Unknown"))
ef416fc2 464 {
465 if (verbose >= 0)
466 {
467 if (!errors && !verbose)
fa73b229 468 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 469
fa73b229 470 _cupsLangPrintf(stdout,
b94498cf 471 _(" **FAIL** BAD Default%s %s\n"
ef416fc2 472 " REF: Page 40, section 4.5.\n"),
473 option->keyword, option->defchoice);
b94498cf 474 }
ef416fc2 475
476 errors ++;
477 }
478 else if (verbose > 0)
fa73b229 479 _cupsLangPrintf(stdout,
b94498cf 480 _(" PASS Default%s\n"),
ef416fc2 481 option->keyword);
482 }
483 else
484 {
485 if (verbose >= 0)
486 {
487 if (!errors && !verbose)
fa73b229 488 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 489
fa73b229 490 _cupsLangPrintf(stdout,
b94498cf 491 _(" **FAIL** REQUIRED Default%s\n"
492 " REF: Page 40, section 4.5.\n"),
493 option->keyword);
494 }
ef416fc2 495
496 errors ++;
497 }
498 }
499
500 if (ppdFindAttr(ppd, "FileVersion", NULL) != NULL)
501 {
502 if (verbose > 0)
fa73b229 503 _cupsLangPuts(stdout, _(" PASS FileVersion\n"));
ef416fc2 504 }
505 else
506 {
507 if (verbose >= 0)
508 {
509 if (!errors && !verbose)
fa73b229 510 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 511
fa73b229 512 _cupsLangPuts(stdout,
ef416fc2 513 _(" **FAIL** REQUIRED FileVersion\n"
514 " REF: Page 56, section 5.3.\n"));
515 }
516
517 errors ++;
518 }
519
520 if (ppdFindAttr(ppd, "FormatVersion", NULL) != NULL)
521 {
522 if (verbose > 0)
fa73b229 523 _cupsLangPuts(stdout, _(" PASS FormatVersion\n"));
ef416fc2 524 }
525 else
526 {
527 if (verbose >= 0)
528 {
529 if (!errors && !verbose)
fa73b229 530 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 531
fa73b229 532 _cupsLangPuts(stdout,
ef416fc2 533 _(" **FAIL** REQUIRED FormatVersion\n"
534 " REF: Page 56, section 5.3.\n"));
535 }
536
537 errors ++;
538 }
539
540 if (ppd->lang_encoding != NULL)
541 {
542 if (verbose > 0)
fa73b229 543 _cupsLangPuts(stdout, _(" PASS LanguageEncoding\n"));
ef416fc2 544 }
545 else if (ppdversion > 40)
546 {
547 if (verbose >= 0)
548 {
549 if (!errors && !verbose)
fa73b229 550 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 551
fa73b229 552 _cupsLangPuts(stdout,
ef416fc2 553 _(" **FAIL** REQUIRED LanguageEncoding\n"
554 " REF: Pages 56-57, section 5.3.\n"));
555 }
556
557 errors ++;
558 }
559
560 if (ppd->lang_version != NULL)
561 {
562 if (verbose > 0)
fa73b229 563 _cupsLangPuts(stdout, _(" PASS LanguageVersion\n"));
ef416fc2 564 }
565 else
566 {
567 if (verbose >= 0)
568 {
569 if (!errors && !verbose)
fa73b229 570 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 571
fa73b229 572 _cupsLangPuts(stdout,
ef416fc2 573 _(" **FAIL** REQUIRED LanguageVersion\n"
574 " REF: Pages 57-58, section 5.3.\n"));
575 }
576
577 errors ++;
578 }
579
580 if (ppd->manufacturer != NULL)
581 {
582 if (!strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) ||
583 !strncasecmp(ppd->manufacturer, "Hewlett Packard", 15))
584 {
585 if (verbose >= 0)
586 {
587 if (!errors && !verbose)
fa73b229 588 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 589
fa73b229 590 _cupsLangPuts(stdout,
ef416fc2 591 _(" **FAIL** BAD Manufacturer (should be "
592 "\"HP\")\n"
593 " REF: Page 211, table D.1.\n"));
594 }
595
596 errors ++;
597 }
b94498cf 598 else if (!strncasecmp(ppd->manufacturer, "OkiData", 7) ||
599 !strncasecmp(ppd->manufacturer, "Oki Data", 8))
600 {
601 if (verbose >= 0)
602 {
603 if (!errors && !verbose)
604 _cupsLangPuts(stdout, _(" FAIL\n"));
605
606 _cupsLangPuts(stdout,
607 _(" **FAIL** BAD Manufacturer (should be "
608 "\"Oki\")\n"
609 " REF: Page 211, table D.1.\n"));
610 }
611
612 errors ++;
613 }
ef416fc2 614 else if (verbose > 0)
fa73b229 615 _cupsLangPuts(stdout, _(" PASS Manufacturer\n"));
ef416fc2 616 }
617 else if (ppdversion >= 43)
618 {
619 if (verbose >= 0)
620 {
621 if (!errors && !verbose)
fa73b229 622 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 623
fa73b229 624 _cupsLangPuts(stdout,
ef416fc2 625 _(" **FAIL** REQUIRED Manufacturer\n"
626 " REF: Pages 58-59, section 5.3.\n"));
627 }
628
629 errors ++;
630 }
631
632 if (ppd->modelname != NULL)
633 {
634 for (ptr = ppd->modelname; *ptr; ptr ++)
635 if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr))
636 break;
637
638 if (*ptr)
639 {
640 if (verbose >= 0)
641 {
642 if (!errors && !verbose)
fa73b229 643 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 644
fa73b229 645 _cupsLangPrintf(stdout,
ef416fc2 646 _(" **FAIL** BAD ModelName - \"%c\" not "
647 "allowed in string.\n"
648 " REF: Pages 59-60, section 5.3.\n"),
649 *ptr);
650 }
651
652 errors ++;
653 }
654 else if (verbose > 0)
fa73b229 655 _cupsLangPuts(stdout, _(" PASS ModelName\n"));
ef416fc2 656 }
657 else
658 {
659 if (verbose >= 0)
660 {
661 if (!errors && !verbose)
fa73b229 662 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 663
fa73b229 664 _cupsLangPuts(stdout,
ef416fc2 665 _(" **FAIL** REQUIRED ModelName\n"
666 " REF: Pages 59-60, section 5.3.\n"));
667 }
668
669 errors ++;
670 }
671
672 if (ppd->nickname != NULL)
673 {
674 if (verbose > 0)
fa73b229 675 _cupsLangPuts(stdout, _(" PASS NickName\n"));
ef416fc2 676 }
677 else
678 {
679 if (verbose >= 0)
680 {
681 if (!errors && !verbose)
fa73b229 682 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 683
fa73b229 684 _cupsLangPuts(stdout,
ef416fc2 685 _(" **FAIL** REQUIRED NickName\n"
686 " REF: Page 60, section 5.3.\n"));
687 }
688
689 errors ++;
690 }
691
692 if (ppdFindOption(ppd, "PageSize") != NULL)
693 {
694 if (verbose > 0)
fa73b229 695 _cupsLangPuts(stdout, _(" PASS PageSize\n"));
ef416fc2 696 }
697 else
698 {
699 if (verbose >= 0)
700 {
701 if (!errors && !verbose)
fa73b229 702 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 703
fa73b229 704 _cupsLangPuts(stdout,
ef416fc2 705 _(" **FAIL** REQUIRED PageSize\n"
706 " REF: Pages 99-100, section 5.14.\n"));
707 }
708
709 errors ++;
710 }
711
712 if (ppdFindOption(ppd, "PageRegion") != NULL)
713 {
714 if (verbose > 0)
fa73b229 715 _cupsLangPuts(stdout, _(" PASS PageRegion\n"));
ef416fc2 716 }
717 else
718 {
719 if (verbose >= 0)
720 {
721 if (!errors && !verbose)
fa73b229 722 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 723
fa73b229 724 _cupsLangPuts(stdout,
ef416fc2 725 _(" **FAIL** REQUIRED PageRegion\n"
726 " REF: Page 100, section 5.14.\n"));
727 }
728
729 errors ++;
730 }
731
732 if (ppd->pcfilename != NULL)
733 {
734 if (verbose > 0)
fa73b229 735 _cupsLangPuts(stdout, _(" PASS PCFileName\n"));
ef416fc2 736 }
737 else
738 {
739 if (verbose >= 0)
740 {
741 if (!errors && !verbose)
fa73b229 742 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 743
fa73b229 744 _cupsLangPuts(stdout,
ef416fc2 745 _(" **FAIL** REQUIRED PCFileName\n"
746 " REF: Pages 61-62, section 5.3.\n"));
747 }
748
749 errors ++;
750 }
751
752 if (ppd->product != NULL)
753 {
754 if (ppd->product[0] != '(' ||
755 ppd->product[strlen(ppd->product) - 1] != ')')
756 {
757 if (verbose >= 0)
758 {
759 if (!errors && !verbose)
fa73b229 760 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 761
fa73b229 762 _cupsLangPuts(stdout,
ef416fc2 763 _(" **FAIL** BAD Product - not \"(string)\".\n"
764 " REF: Page 62, section 5.3.\n"));
765 }
766
767 errors ++;
768 }
769 else if (verbose > 0)
fa73b229 770 _cupsLangPuts(stdout, _(" PASS Product\n"));
ef416fc2 771 }
772 else
773 {
774 if (verbose >= 0)
775 {
776 if (!errors && !verbose)
fa73b229 777 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 778
fa73b229 779 _cupsLangPuts(stdout,
ef416fc2 780 _(" **FAIL** REQUIRED Product\n"
781 " REF: Page 62, section 5.3.\n"));
782 }
783
784 errors ++;
785 }
786
787 if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL &&
788 attr->value != NULL)
789 {
790 char junkstr[255]; /* Temp string */
791 int junkint; /* Temp integer */
792
793
794 if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2)
795 {
796 if (verbose >= 0)
797 {
798 if (!errors && !verbose)
fa73b229 799 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 800
fa73b229 801 _cupsLangPuts(stdout,
ef416fc2 802 _(" **FAIL** BAD PSVersion - not \"(string) "
803 "int\".\n"
804 " REF: Pages 62-64, section 5.3.\n"));
805 }
806
807 errors ++;
808 }
809 else if (verbose > 0)
fa73b229 810 _cupsLangPuts(stdout, _(" PASS PSVersion\n"));
ef416fc2 811 }
812 else
813 {
814 if (verbose >= 0)
815 {
816 if (!errors && !verbose)
fa73b229 817 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 818
fa73b229 819 _cupsLangPuts(stdout,
ef416fc2 820 _(" **FAIL** REQUIRED PSVersion\n"
821 " REF: Pages 62-64, section 5.3.\n"));
822 }
823
824 errors ++;
825 }
826
827 if (ppd->shortnickname != NULL)
828 {
829 if (strlen(ppd->shortnickname) > 31)
830 {
831 if (verbose >= 0)
832 {
833 if (!errors && !verbose)
fa73b229 834 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 835
fa73b229 836 _cupsLangPuts(stdout,
ef416fc2 837 _(" **FAIL** BAD ShortNickName - longer "
838 "than 31 chars.\n"
839 " REF: Pages 64-65, section 5.3.\n"));
840 }
841
842 errors ++;
843 }
844 else if (verbose > 0)
fa73b229 845 _cupsLangPuts(stdout, _(" PASS ShortNickName\n"));
ef416fc2 846 }
847 else if (ppdversion >= 43)
848 {
849 if (verbose >= 0)
850 {
851 if (!errors && !verbose)
fa73b229 852 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 853
fa73b229 854 _cupsLangPuts(stdout,
ef416fc2 855 _(" **FAIL** REQUIRED ShortNickName\n"
856 " REF: Page 64-65, section 5.3.\n"));
857 }
858
859 errors ++;
860 }
861
862 if (ppd->patches != NULL && strchr(ppd->patches, '\"') &&
863 strstr(ppd->patches, "*End"))
864 {
865 if (verbose >= 0)
866 {
867 if (!errors && !verbose)
fa73b229 868 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 869
fa73b229 870 _cupsLangPuts(stdout,
ef416fc2 871 _(" **FAIL** BAD JobPatchFile attribute in file\n"
872 " REF: Page 24, section 3.4.\n"));
873 }
874
875 errors ++;
876 }
877
878 /*
879 * Check for page sizes without the corresponding ImageableArea or
880 * PaperDimension values...
881 */
882
883 if (ppd->num_sizes == 0)
884 {
885 if (verbose >= 0)
886 {
887 if (!errors && !verbose)
fa73b229 888 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 889
fa73b229 890 _cupsLangPuts(stdout,
ef416fc2 891 _(" **FAIL** REQUIRED PageSize\n"
892 " REF: Page 41, section 5.\n"
893 " REF: Page 99, section 5.14.\n"));
894 }
895
896 errors ++;
897 }
898 else
899 {
900 for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++)
901 {
902 /*
903 * Don't check custom size...
904 */
905
906 if (!strcmp(size->name, "Custom"))
907 continue;
908
909 /*
910 * Check for ImageableArea...
911 */
912
913 if (size->left == 0.0 && size->bottom == 0.0 &&
914 size->right == 0.0 && size->top == 0.0)
915 {
916 if (verbose >= 0)
917 {
918 if (!errors && !verbose)
fa73b229 919 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 920
fa73b229 921 _cupsLangPrintf(stdout,
ef416fc2 922 _(" **FAIL** REQUIRED ImageableArea for "
923 "PageSize %s\n"
924 " REF: Page 41, section 5.\n"
925 " REF: Page 102, section 5.15.\n"),
926 size->name);
927 }
928
929 errors ++;
930 }
931
932 /*
933 * Check for PaperDimension...
934 */
935
936 if (size->width == 0.0 && size->length == 0.0)
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** REQUIRED PaperDimension "
945 "for PageSize %s\n"
946 " REF: Page 41, section 5.\n"
947 " REF: Page 103, section 5.15.\n"),
948 size->name);
949 }
950
951 errors ++;
952 }
953 }
954 }
955
956 /*
957 * Check for valid Resolution, JCLResolution, or SetResolution values...
958 */
959
960 if ((option = ppdFindOption(ppd, "Resolution")) == NULL)
961 if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL)
962 option = ppdFindOption(ppd, "SetResolution");
963
964 if (option != NULL)
965 {
966 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
967 {
968 /*
969 * Verify that all resolution options are of the form NNNdpi
970 * or NNNxNNNdpi...
971 */
972
973 xdpi = strtol(choice->choice, (char **)&ptr, 10);
974 if (ptr > choice->choice && xdpi > 0)
975 {
976 if (*ptr == 'x')
977 ydpi = strtol(ptr + 1, (char **)&ptr, 10);
978 else
979 ydpi = xdpi;
980 }
981 else
982 ydpi = xdpi;
983
984 if (xdpi <= 0 || ydpi <= 0 || strcmp(ptr, "dpi"))
985 {
986 if (verbose >= 0)
987 {
988 if (!errors && !verbose)
fa73b229 989 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 990
fa73b229 991 _cupsLangPrintf(stdout,
ef416fc2 992 _(" **FAIL** Bad %s choice %s!\n"
993 " REF: Page 84, section 5.9\n"),
994 option->keyword, choice->choice);
995 }
996
997 errors ++;
998 }
999 }
1000 }
1001
1002 /*
1003 * Check for a duplex option, and for standard values...
1004 */
1005
1006 if ((option = ppdFindOption(ppd, "Duplex")) == NULL)
1007 if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
1008 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
1009 option = ppdFindOption(ppd, "KD03Duplex");
1010
1011 if (option != NULL)
1012 {
1013 if (ppdFindChoice(option, "None") == NULL)
1014 {
1015 if (verbose >= 0)
1016 {
1017 if (!errors && !verbose)
fa73b229 1018 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 1019
fa73b229 1020 _cupsLangPrintf(stdout,
ef416fc2 1021 _(" **FAIL** REQUIRED %s does not define "
1022 "choice None!\n"
1023 " REF: Page 122, section 5.17\n"),
1024 option->keyword);
1025 }
1026
1027 errors ++;
1028 }
1029
1030 for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
1031 if (strcmp(choice->choice, "None") &&
1032 strcmp(choice->choice, "DuplexNoTumble") &&
1033 strcmp(choice->choice, "DuplexTumble") &&
1034 strcmp(choice->choice, "SimplexTumble"))
1035 {
1036 if (verbose >= 0)
1037 {
1038 if (!errors && !verbose)
fa73b229 1039 _cupsLangPuts(stdout, _(" FAIL\n"));
ef416fc2 1040
fa73b229 1041 _cupsLangPrintf(stdout,
ef416fc2 1042 _(" **FAIL** Bad %s choice %s!\n"
1043 " REF: Page 122, section 5.17\n"),
1044 option->keyword, choice->choice);
1045 }
1046
1047 errors ++;
1048 }
1049 }
1050
b94498cf 1051 if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
1052 strcmp(attr->name, "1284DeviceID"))
b423cd4c 1053 {
b94498cf 1054 if (verbose >= 0)
1055 {
1056 if (!errors && !verbose)
1057 _cupsLangPuts(stdout, _(" FAIL\n"));
b423cd4c 1058
b94498cf 1059 _cupsLangPrintf(stdout,
1060 _(" **FAIL** %s must be 1284DeviceID!\n"
1061 " REF: Page 72, section 5.5\n"),
1062 attr->name);
1063 }
b423cd4c 1064
b94498cf 1065 errors ++;
1066 }
b423cd4c 1067
b94498cf 1068 if (!(warn & WARN_CONSTRAINTS))
1069 errors = check_constraints(ppd, errors, verbose, 0);
c0e1af83 1070
b94498cf 1071 if (!(warn & WARN_FILTERS))
1072 errors = check_filters(ppd, root, errors, verbose, 0);
b423cd4c 1073
b94498cf 1074 if (!(warn & WARN_TRANSLATIONS))
1075 errors = check_translations(ppd, errors, verbose, 0);
b423cd4c 1076
b94498cf 1077 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
1078 attr->value)
1079 {
1080 /*
1081 * This file contains localizations, check for conformance of the
1082 * base translation...
1083 */
b423cd4c 1084
b94498cf 1085 if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL)
1086 {
1087 if (!attr->value || strcmp(attr->value, "ISOLatin1"))
1088 {
1089 if (!errors && !verbose)
1090 _cupsLangPuts(stdout, _(" FAIL\n"));
b423cd4c 1091
b94498cf 1092 if (verbose >= 0)
bc44d920 1093 _cupsLangPrintf(stdout,
b94498cf 1094 _(" **FAIL** Bad LanguageEncoding %s - "
1095 "must be ISOLatin1!\n"),
1096 attr->value ? attr->value : "(null)");
b423cd4c 1097
b94498cf 1098 errors ++;
1099 }
b423cd4c 1100
b94498cf 1101 if (!ppd->lang_version || strcmp(ppd->lang_version, "English"))
b423cd4c 1102 {
b94498cf 1103 if (!errors && !verbose)
1104 _cupsLangPuts(stdout, _(" FAIL\n"));
b423cd4c 1105
b94498cf 1106 if (verbose >= 0)
bc44d920 1107 _cupsLangPrintf(stdout,
b94498cf 1108 _(" **FAIL** Bad LanguageVersion %s - "
1109 "must be English!\n"),
1110 ppd->lang_version ? ppd->lang_version : "(null)");
b423cd4c 1111
b94498cf 1112 errors ++;
b423cd4c 1113 }
b94498cf 1114
1115 /*
b423cd4c 1116 * Loop through all options and choices...
1117 */
1118
b94498cf 1119 for (option = ppdFirstOption(ppd);
b423cd4c 1120 option;
1121 option = ppdNextOption(ppd))
1122 {
b94498cf 1123 /*
1124 * Check for special characters outside A0 to BF, F7, or F8
1125 * that are used for languages other than English.
1126 */
b423cd4c 1127
b94498cf 1128 for (ptr = option->text; *ptr; ptr ++)
1129 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
1130 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
1131 break;
b423cd4c 1132
b94498cf 1133 if (*ptr)
f7deaa1a 1134 {
b94498cf 1135 if (!errors && !verbose)
1136 _cupsLangPuts(stdout, _(" FAIL\n"));
b423cd4c 1137
b423cd4c 1138 if (verbose >= 0)
b423cd4c 1139 _cupsLangPrintf(stdout,
b94498cf 1140 _(" **FAIL** Default translation "
b423cd4c 1141 "string for option %s contains 8-bit "
1142 "characters!\n"),
1143 option->keyword);
b423cd4c 1144
1145 errors ++;
1146 }
1147
b94498cf 1148 for (j = 0; j < option->num_choices; j ++)
b423cd4c 1149 {
b94498cf 1150 /*
1151 * Check for special characters outside A0 to BF, F7, or F8
1152 * that are used for languages other than English.
1153 */
d09495fa 1154
b94498cf 1155 for (ptr = option->choices[j].text; *ptr; ptr ++)
1156 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
1157 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
1158 break;
b423cd4c 1159
b94498cf 1160 if (*ptr)
f7deaa1a 1161 {
b94498cf 1162 if (!errors && !verbose)
1163 _cupsLangPuts(stdout, _(" FAIL\n"));
b423cd4c 1164
b423cd4c 1165 if (verbose >= 0)
b423cd4c 1166 _cupsLangPrintf(stdout,
b94498cf 1167 _(" **FAIL** Default translation "
b423cd4c 1168 "string for option %s choice %s contains "
1169 "8-bit characters!\n"),
1170 option->keyword,
1171 option->choices[j].choice);
b423cd4c 1172
1173 errors ++;
1174 }
b94498cf 1175 }
b423cd4c 1176 }
b94498cf 1177 }
1178 }
c0e1af83 1179
b94498cf 1180 /*
1181 * Final pass/fail notification...
1182 */
c0e1af83 1183
b94498cf 1184 if (errors)
1185 status = ERROR_CONFORMANCE;
1186 else if (!verbose)
1187 _cupsLangPuts(stdout, _(" PASS\n"));
c0e1af83 1188
b94498cf 1189 if (verbose >= 0)
1190 {
1191 check_basics(argv[i]);
c0e1af83 1192
b94498cf 1193 if (warn & WARN_CONSTRAINTS)
1194 errors = check_constraints(ppd, errors, verbose, 1);
c0e1af83 1195
b94498cf 1196 if (warn & WARN_DEFAULTS)
1197 errors = check_defaults(ppd, errors, verbose, 1);
c0e1af83 1198
b94498cf 1199 if (warn & WARN_FILTERS)
1200 errors = check_filters(ppd, root, errors, verbose, 1);
c0e1af83 1201
b94498cf 1202 if (warn & WARN_TRANSLATIONS)
1203 errors = check_translations(ppd, errors, verbose, 1);
c0e1af83 1204
1205 /*
b94498cf 1206 * Look for default keywords with no corresponding option...
c0e1af83 1207 */
1208
b94498cf 1209 for (j = 0; j < ppd->num_attrs; j ++)
1210 {
1211 attr = ppd->attrs[j];
323c5de1 1212
b94498cf 1213 if (!strcmp(attr->name, "DefaultColorSpace") ||
1214 !strcmp(attr->name, "DefaultColorSep") ||
1215 !strcmp(attr->name, "DefaultFont") ||
09a101d6 1216 !strcmp(attr->name, "DefaultHalftoneType") ||
b94498cf 1217 !strcmp(attr->name, "DefaultImageableArea") ||
09a101d6 1218 !strcmp(attr->name, "DefaultLeadingEdge") ||
b94498cf 1219 !strcmp(attr->name, "DefaultOutputOrder") ||
1220 !strcmp(attr->name, "DefaultPaperDimension") ||
09a101d6 1221 !strcmp(attr->name, "DefaultResolution") ||
b94498cf 1222 !strcmp(attr->name, "DefaultScreenProc") ||
1223 !strcmp(attr->name, "DefaultTransfer"))
1224 continue;
b423cd4c 1225
b94498cf 1226 if (!strncmp(attr->name, "Default", 7) &&
1227 !ppdFindOption(ppd, attr->name + 7))
1228 _cupsLangPrintf(stdout,
1229 _(" WARN %s has no corresponding "
1230 "options!\n"),
1231 attr->name);
323c5de1 1232 }
323c5de1 1233
b94498cf 1234 /*
1235 * Check for old Duplex option names...
1236 */
89d46774 1237
1238 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
1239 option = ppdFindOption(ppd, "KD03Duplex");
1240
1241 if (option)
ef416fc2 1242 {
fa73b229 1243 _cupsLangPrintf(stdout,
ef416fc2 1244 _(" WARN Duplex option keyword %s "
1245 "should be named Duplex or JCLDuplex!\n"
1246 " REF: Page 122, section 5.17\n"),
1247 option->keyword);
1248 }
1249
1250 ppdMarkDefaults(ppd);
1251 if (ppdConflicts(ppd))
1252 {
fa73b229 1253 _cupsLangPuts(stdout,
ef416fc2 1254 _(" WARN Default choices conflicting!\n"));
1255
1256 show_conflicts(ppd);
1257 }
1258
1259 if (ppdversion < 43)
1260 {
fa73b229 1261 _cupsLangPrintf(stdout,
ef416fc2 1262 _(" WARN Obsolete PPD version %.1f!\n"
1263 " REF: Page 42, section 5.2.\n"),
1264 0.1f * ppdversion);
1265 }
1266
1267 if (!ppd->lang_encoding && ppdversion < 41)
1268 {
fa73b229 1269 _cupsLangPuts(stdout,
ef416fc2 1270 _(" WARN LanguageEncoding required by PPD "
1271 "4.3 spec.\n"
1272 " REF: Pages 56-57, section 5.3.\n"));
1273 }
1274
1275 if (!ppd->manufacturer && ppdversion < 43)
1276 {
fa73b229 1277 _cupsLangPuts(stdout,
ef416fc2 1278 _(" WARN Manufacturer required by PPD "
1279 "4.3 spec.\n"
1280 " REF: Pages 58-59, section 5.3.\n"));
1281 }
1282
1283 /*
1284 * Treat a PCFileName attribute longer than 12 characters as
1285 * a warning and not a hard error...
1286 */
1287
1288 if (ppd->pcfilename && strlen(ppd->pcfilename) > 12)
1289 {
fa73b229 1290 _cupsLangPuts(stdout,
ef416fc2 1291 _(" WARN PCFileName longer than 8.3 in "
1292 "violation of PPD spec.\n"
1293 " REF: Pages 61-62, section 5.3.\n"));
1294 }
1295
1296 if (!ppd->shortnickname && ppdversion < 43)
1297 {
fa73b229 1298 _cupsLangPuts(stdout,
ef416fc2 1299 _(" WARN ShortNickName required by PPD "
1300 "4.3 spec.\n"
1301 " REF: Pages 64-65, section 5.3.\n"));
1302 }
1303
1304 /*
1305 * Check the Protocols line and flag PJL + BCP since TBCP is
1306 * usually used with PJL...
1307 */
1308
1309 if (ppd->protocols)
1310 {
1311 if (strstr(ppd->protocols, "PJL") &&
1312 strstr(ppd->protocols, "BCP") &&
1313 !strstr(ppd->protocols, "TBCP"))
1314 {
fa73b229 1315 _cupsLangPuts(stdout,
ef416fc2 1316 _(" WARN Protocols contains both PJL "
1317 "and BCP; expected TBCP.\n"
1318 " REF: Pages 78-79, section 5.7.\n"));
1319 }
1320
1321 if (strstr(ppd->protocols, "PJL") &&
1322 (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps))
1323 {
fa73b229 1324 _cupsLangPuts(stdout,
ef416fc2 1325 _(" WARN Protocols contains PJL but JCL "
1326 "attributes are not set.\n"
1327 " REF: Pages 78-79, section 5.7.\n"));
1328 }
1329 }
1330
1331 /*
1332 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1333 * which are errors according to the spec but won't cause problems
1334 * with CUPS specifically...
1335 */
1336
1337 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1338 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1339 {
1340 len = strlen(option->keyword);
1341
1342 for (m = 0, group2 = ppd->groups;
1343 m < ppd->num_groups;
1344 m ++, group2 ++)
1345 for (n = 0, option2 = group2->options;
1346 n < group2->num_options;
1347 n ++, option2 ++)
1348 if (option != option2 &&
1349 len < strlen(option2->keyword) &&
1350 !strncmp(option->keyword, option2->keyword, len))
1351 {
fa73b229 1352 _cupsLangPrintf(stdout,
ef416fc2 1353 _(" WARN %s shares a common "
1354 "prefix with %s\n"
1355 " REF: Page 15, section "
1356 "3.2.\n"),
1357 option->keyword, option2->keyword);
1358 }
1359 }
1360 }
1361
323c5de1 1362 /*
1363 * cupsICCProfile
1364 */
1365
1366 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
1367 attr != NULL;
1368 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
1369 {
1370 if (attr->value)
1371 {
1372 if (attr->value[0] == '/')
1373 snprintf(pathprog, sizeof(pathprog), "%s%s", root, attr->value);
1374 else
1375 {
1376 if ((ptr = getenv("CUPS_DATADIR")) == NULL)
1377 ptr = CUPS_DATADIR;
1378
1379 if (*ptr == '/' || !*root)
1380 snprintf(pathprog, sizeof(pathprog), "%s%s/profiles/%s", root,
1381 ptr, attr->value);
1382 else
1383 snprintf(pathprog, sizeof(pathprog), "%s/%s/profiles/%s", root,
1384 ptr, attr->value);
1385 }
1386 }
1387
1388 if (!attr->value || !attr->value[0] || stat(pathprog, &statbuf))
1389 {
1390 if (verbose >= 0)
1391 _cupsLangPrintf(stdout,
1392 _(" WARN Missing cupsICCProfile "
1393 "file \"%s\"\n"),
1394 !attr->value || !attr->value[0] ? "<NULL>" :
1395 attr->value);
1396 }
1397 }
1398
1399#ifdef __APPLE__
1400 /*
1401 * APDialogExtension
1402 */
1403
1404 for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL);
1405 attr != NULL;
1406 attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
1407 {
1408 if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0)
1409 _cupsLangPrintf(stdout, _(" WARN Missing "
1410 "APDialogExtension file \"%s\"\n"),
1411 attr->value ? attr->value : "<NULL>");
1412 }
1413
1414 /*
1415 * APPrinterIconPath
1416 */
1417
1418 for (attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL);
1419 attr != NULL;
1420 attr = ppdFindNextAttr(ppd, "APPrinterIconPath", NULL))
1421 {
1422 if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0)
1423 _cupsLangPrintf(stdout, _(" WARN Missing "
1424 "APPrinterIconPath file \"%s\"\n"),
1425 attr->value ? attr->value : "<NULL>");
1426 }
1427#endif /* __APPLE__ */
1428
ef416fc2 1429 if (verbose > 0)
1430 {
1431 if (errors)
f7deaa1a 1432 _cupsLangPrintf(stdout, _(" %d ERRORS FOUND\n"), errors);
ef416fc2 1433 else
fa73b229 1434 _cupsLangPuts(stdout, _(" NO ERRORS FOUND\n"));
ef416fc2 1435 }
1436
ef416fc2 1437 /*
1438 * Then list the options, if "-v" was provided...
1439 */
1440
1441 if (verbose > 1)
1442 {
fa73b229 1443 _cupsLangPrintf(stdout,
ef416fc2 1444 "\n"
1445 " language_level = %d\n"
1446 " color_device = %s\n"
1447 " variable_sizes = %s\n"
1448 " landscape = %d\n",
1449 ppd->language_level,
1450 ppd->color_device ? "TRUE" : "FALSE",
1451 ppd->variable_sizes ? "TRUE" : "FALSE",
1452 ppd->landscape);
1453
1454 switch (ppd->colorspace)
1455 {
1456 case PPD_CS_CMYK :
fa73b229 1457 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMYK\n");
ef416fc2 1458 break;
1459 case PPD_CS_CMY :
fa73b229 1460 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMY\n");
ef416fc2 1461 break;
1462 case PPD_CS_GRAY :
fa73b229 1463 _cupsLangPuts(stdout, " colorspace = PPD_CS_GRAY\n");
ef416fc2 1464 break;
1465 case PPD_CS_RGB :
fa73b229 1466 _cupsLangPuts(stdout, " colorspace = PPD_CS_RGB\n");
ef416fc2 1467 break;
1468 default :
fa73b229 1469 _cupsLangPuts(stdout, " colorspace = <unknown>\n");
ef416fc2 1470 break;
1471 }
1472
fa73b229 1473 _cupsLangPrintf(stdout, " num_emulations = %d\n",
ef416fc2 1474 ppd->num_emulations);
1475 for (j = 0; j < ppd->num_emulations; j ++)
fa73b229 1476 _cupsLangPrintf(stdout, " emulations[%d] = %s\n",
ef416fc2 1477 j, ppd->emulations[j].name);
1478
fa73b229 1479 _cupsLangPrintf(stdout, " lang_encoding = %s\n",
ef416fc2 1480 ppd->lang_encoding);
fa73b229 1481 _cupsLangPrintf(stdout, " lang_version = %s\n",
ef416fc2 1482 ppd->lang_version);
fa73b229 1483 _cupsLangPrintf(stdout, " modelname = %s\n", ppd->modelname);
1484 _cupsLangPrintf(stdout, " ttrasterizer = %s\n",
ef416fc2 1485 ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer);
fa73b229 1486 _cupsLangPrintf(stdout, " manufacturer = %s\n",
ef416fc2 1487 ppd->manufacturer);
fa73b229 1488 _cupsLangPrintf(stdout, " product = %s\n", ppd->product);
1489 _cupsLangPrintf(stdout, " nickname = %s\n", ppd->nickname);
1490 _cupsLangPrintf(stdout, " shortnickname = %s\n",
ef416fc2 1491 ppd->shortnickname);
fa73b229 1492 _cupsLangPrintf(stdout, " patches = %d bytes\n",
ef416fc2 1493 ppd->patches == NULL ? 0 : (int)strlen(ppd->patches));
1494
fa73b229 1495 _cupsLangPrintf(stdout, " num_groups = %d\n", ppd->num_groups);
ef416fc2 1496 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1497 {
fa73b229 1498 _cupsLangPrintf(stdout, " group[%d] = %s\n",
ef416fc2 1499 j, group->text);
1500
1501 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1502 {
fa73b229 1503 _cupsLangPrintf(stdout,
ef416fc2 1504 " options[%d] = %s (%s) %s %s %.0f "
1505 "(%d choices)\n",
1506 k, option->keyword, option->text, uis[option->ui],
1507 sections[option->section], option->order,
1508 option->num_choices);
1509
1510 if (!strcmp(option->keyword, "PageSize") ||
1511 !strcmp(option->keyword, "PageRegion"))
1512 {
1513 for (m = option->num_choices, choice = option->choices;
1514 m > 0;
1515 m --, choice ++)
1516 {
1517 size = ppdPageSize(ppd, choice->choice);
1518
1519 if (size == NULL)
fa73b229 1520 _cupsLangPrintf(stdout,
ef416fc2 1521 " %s (%s) = ERROR",
1522 choice->choice, choice->text);
1523 else
fa73b229 1524 _cupsLangPrintf(stdout,
ef416fc2 1525 " %s (%s) = %.2fx%.2fin "
1526 "(%.1f,%.1f,%.1f,%.1f)",
1527 choice->choice, choice->text,
1528 size->width / 72.0, size->length / 72.0,
1529 size->left / 72.0, size->bottom / 72.0,
1530 size->right / 72.0, size->top / 72.0);
1531
1532 if (!strcmp(option->defchoice, choice->choice))
fa73b229 1533 _cupsLangPuts(stdout, " *\n");
ef416fc2 1534 else
fa73b229 1535 _cupsLangPuts(stdout, "\n");
ef416fc2 1536 }
1537 }
1538 else
1539 {
1540 for (m = option->num_choices, choice = option->choices;
1541 m > 0;
1542 m --, choice ++)
1543 {
fa73b229 1544 _cupsLangPrintf(stdout, " %s (%s)",
ef416fc2 1545 choice->choice, choice->text);
1546
1547 if (!strcmp(option->defchoice, choice->choice))
fa73b229 1548 _cupsLangPuts(stdout, " *\n");
ef416fc2 1549 else
fa73b229 1550 _cupsLangPuts(stdout, "\n");
ef416fc2 1551 }
1552 }
1553 }
1554 }
1555
09a101d6 1556 _cupsLangPrintf(stdout, " num_consts = %d\n",
1557 ppd->num_consts);
1558 for (j = 0; j < ppd->num_consts; j ++)
1559 _cupsLangPrintf(stdout,
1560 " consts[%d] = *%s %s *%s %s\n",
1561 j, ppd->consts[j].option1, ppd->consts[j].choice1,
1562 ppd->consts[j].option2, ppd->consts[j].choice2);
1563
fa73b229 1564 _cupsLangPrintf(stdout, " num_profiles = %d\n",
ef416fc2 1565 ppd->num_profiles);
1566 for (j = 0; j < ppd->num_profiles; j ++)
fa73b229 1567 _cupsLangPrintf(stdout,
ef416fc2 1568 " profiles[%d] = %s/%s %.3f %.3f "
1569 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]\n",
1570 j, ppd->profiles[j].resolution,
1571 ppd->profiles[j].media_type,
1572 ppd->profiles[j].gamma, ppd->profiles[j].density,
1573 ppd->profiles[j].matrix[0][0],
1574 ppd->profiles[j].matrix[0][1],
1575 ppd->profiles[j].matrix[0][2],
1576 ppd->profiles[j].matrix[1][0],
1577 ppd->profiles[j].matrix[1][1],
1578 ppd->profiles[j].matrix[1][2],
1579 ppd->profiles[j].matrix[2][0],
1580 ppd->profiles[j].matrix[2][1],
1581 ppd->profiles[j].matrix[2][2]);
1582
fa73b229 1583 _cupsLangPrintf(stdout, " num_fonts = %d\n", ppd->num_fonts);
ef416fc2 1584 for (j = 0; j < ppd->num_fonts; j ++)
fa73b229 1585 _cupsLangPrintf(stdout, " fonts[%d] = %s\n",
ef416fc2 1586 j, ppd->fonts[j]);
1587
fa73b229 1588 _cupsLangPrintf(stdout, " num_attrs = %d\n", ppd->num_attrs);
ef416fc2 1589 for (j = 0; j < ppd->num_attrs; j ++)
fa73b229 1590 _cupsLangPrintf(stdout,
ef416fc2 1591 " attrs[%d] = %s %s%s%s: \"%s\"\n", j,
1592 ppd->attrs[j]->name, ppd->attrs[j]->spec,
1593 ppd->attrs[j]->text[0] ? "/" : "",
1594 ppd->attrs[j]->text,
1595 ppd->attrs[j]->value ?
1596 ppd->attrs[j]->value : "(null)");
1597 }
1598
1599 ppdClose(ppd);
1600 }
1601
1602 if (!files)
1603 usage();
1604
1605 return (status);
1606}
1607
1608
fa73b229 1609/*
1610 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1611 */
1612
3d8365b8 1613static void
fa73b229 1614check_basics(const char *filename) /* I - PPD file to check */
1615{
1616 cups_file_t *fp; /* File pointer */
1617 int ch; /* Current character */
1618 int col, /* Current column */
1619 whitespace; /* Only seen whitespace? */
1620 int eol; /* Line endings */
1621 int linenum; /* Line number */
1622 int mixed; /* Mixed line endings? */
1623
1624
1625 if ((fp = cupsFileOpen(filename, "r")) == NULL)
1626 return;
1627
1628 linenum = 1;
1629 col = 0;
1630 eol = EOL_NONE;
1631 mixed = 0;
1632 whitespace = 1;
1633
1634 while ((ch = cupsFileGetChar(fp)) != EOF)
1635 {
1636 if (ch == '\r' || ch == '\n')
1637 {
1638 if (ch == '\n')
1639 {
1640 if (eol == EOL_NONE)
1641 eol = EOL_LF;
1642 else if (eol != EOL_LF)
1643 mixed = 1;
1644 }
1645 else if (ch == '\r')
1646 {
1647 if (cupsFilePeekChar(fp) == '\n')
1648 {
1649 cupsFileGetChar(fp);
1650
1651 if (eol == EOL_NONE)
1652 eol = EOL_CRLF;
1653 else
1654 mixed = 1;
1655 }
1656 else if (eol == EOL_NONE)
1657 eol = EOL_CR;
1658 else
1659 mixed = 1;
1660 }
1661
1662 if (col > 0 && whitespace)
1663 _cupsLangPrintf(stdout,
1664 _(" WARN Line %d only contains whitespace!\n"),
1665 linenum);
1666
1667 linenum ++;
1668 col = 0;
1669 whitespace = 1;
1670 }
1671 else
1672 {
1673 if (ch != ' ' && ch != '\t')
1674 whitespace = 0;
1675
1676 col ++;
1677 }
1678 }
1679
1680 if (mixed)
1681 _cupsLangPuts(stdout,
1682 _(" WARN File contains a mix of CR, LF, and "
1683 "CR LF line endings!\n"));
1684
1685 if (eol == EOL_CRLF)
1686 _cupsLangPuts(stdout,
1687 _(" WARN Non-Windows PPD files should use lines "
1688 "ending with only LF, not CR LF!\n"));
1689
1690 cupsFileClose(fp);
1691}
1692
1693
b94498cf 1694/*
1695 * 'check_constraints()' - Check UIConstraints in the PPD file.
1696 */
1697
3d8365b8 1698static int /* O - Errors found */
b94498cf 1699check_constraints(ppd_file_t *ppd, /* I - PPD file */
1700 int errors, /* I - Errors found */
1701 int verbose, /* I - Verbosity level */
1702 int warn) /* I - Warnings only? */
1703{
1704 int j; /* Looping var */
1705 ppd_const_t *c; /* Current constraint */
1706 ppd_option_t *option; /* Standard UI option */
1707 ppd_option_t *option2; /* Standard UI option */
1708 const char *prefix; /* WARN/FAIL prefix */
1709
1710
1711 prefix = warn ? " WARN " : "**FAIL**";
1712
1713 for (j = ppd->num_consts, c = ppd->consts; j > 0; j --, c ++)
1714 {
1715 option = ppdFindOption(ppd, c->option1);
1716 option2 = ppdFindOption(ppd, c->option2);
1717
1718 if (!option || !option2)
1719 {
1720 if (!warn && !errors && !verbose)
1721 _cupsLangPuts(stdout, _(" FAIL\n"));
1722
1723 if (!option)
1724 _cupsLangPrintf(stdout,
1725 _(" %s Missing option %s in "
1726 "UIConstraint \"*%s %s *%s %s\"!\n"),
1727 prefix, c->option1,
1728 c->option1, c->choice1, c->option2, c->choice2);
1729
1730 if (!option2)
1731 _cupsLangPrintf(stdout,
1732 _(" %s Missing option %s in "
1733 "UIConstraint \"*%s %s *%s %s\"!\n"),
1734 prefix, c->option2,
1735 c->option1, c->choice1, c->option2, c->choice2);
1736
1737 if (!warn)
1738 errors ++;
1739
1740 continue;
1741 }
1742
1743 if (c->choice1[0] && !ppdFindChoice(option, c->choice1))
1744 {
1745 if (!warn && !errors && !verbose)
1746 _cupsLangPuts(stdout, _(" FAIL\n"));
1747
1748 _cupsLangPrintf(stdout,
1749 _(" %s Missing choice *%s %s in "
1750 "UIConstraint \"*%s %s *%s %s\"!\n"),
1751 prefix, c->option1, c->choice1,
1752 c->option1, c->choice1, c->option2, c->choice2);
1753
1754 if (!warn)
1755 errors ++;
1756 }
1757
1758 if (c->choice2[0] && !ppdFindChoice(option2, c->choice2))
1759 {
1760 if (!warn && !errors && !verbose)
1761 _cupsLangPuts(stdout, _(" FAIL\n"));
1762
1763 _cupsLangPrintf(stdout,
1764 _(" %s Missing choice *%s %s in "
1765 "UIConstraint \"*%s %s *%s %s\"!\n"),
1766 prefix, c->option2, c->choice2,
1767 c->option1, c->choice1, c->option2, c->choice2);
1768
1769 if (!warn)
1770 errors ++;
1771 }
1772 }
1773
1774 return (errors);
1775}
1776
1777
1778/*
1779 * 'check_defaults()' - Check default option keywords in the PPD file.
1780 */
1781
3d8365b8 1782static int /* O - Errors found */
b94498cf 1783check_defaults(ppd_file_t *ppd, /* I - PPD file */
1784 int errors, /* I - Errors found */
1785 int verbose, /* I - Verbosity level */
1786 int warn) /* I - Warnings only? */
1787{
1788 int j, k; /* Looping vars */
1789 ppd_attr_t *attr; /* PPD attribute */
1790 ppd_option_t *option; /* Standard UI option */
1791 const char *prefix; /* WARN/FAIL prefix */
1792
1793
1794 prefix = warn ? " WARN " : "**FAIL**";
1795
1796 for (j = 0; j < ppd->num_attrs; j ++)
1797 {
1798 attr = ppd->attrs[j];
1799
1800 if (!strcmp(attr->name, "DefaultColorSpace") ||
1801 !strcmp(attr->name, "DefaultFont") ||
09a101d6 1802 !strcmp(attr->name, "DefaultHalftoneType") ||
b94498cf 1803 !strcmp(attr->name, "DefaultImageableArea") ||
09a101d6 1804 !strcmp(attr->name, "DefaultLeadingEdge") ||
b94498cf 1805 !strcmp(attr->name, "DefaultOutputOrder") ||
1806 !strcmp(attr->name, "DefaultPaperDimension") ||
1807 !strcmp(attr->name, "DefaultResolution") ||
1808 !strcmp(attr->name, "DefaultTransfer"))
1809 continue;
1810
1811 if (!strncmp(attr->name, "Default", 7))
1812 {
1813 if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
1814 strcmp(attr->value, "Unknown"))
1815 {
1816 /*
1817 * Check that the default option value matches a choice...
1818 */
1819
1820 for (k = 0; k < option->num_choices; k ++)
1821 if (!strcmp(option->choices[k].choice, attr->value))
1822 break;
1823
1824 if (k >= option->num_choices)
1825 {
1826 if (!warn && !errors && !verbose)
1827 _cupsLangPuts(stdout, _(" FAIL\n"));
1828
1829 if (verbose >= 0)
1830 _cupsLangPrintf(stdout,
1831 _(" %s %s %s does not exist!\n"),
1832 prefix, attr->name, attr->value);
1833
1834 if (!warn)
1835 errors ++;
1836 }
1837 }
1838 }
1839 }
1840
1841 return (errors);
1842}
1843
1844
1845/*
1846 * 'check_filters()' - Check filters in the PPD file.
1847 */
1848
3d8365b8 1849static int /* O - Errors found */
b94498cf 1850check_filters(ppd_file_t *ppd, /* I - PPD file */
1851 const char *root, /* I - Root directory */
1852 int errors, /* I - Errors found */
1853 int verbose, /* I - Verbosity level */
1854 int warn) /* I - Warnings only? */
1855{
1856 ppd_attr_t *attr; /* PPD attribute */
1857 const char *ptr; /* Pointer into string */
1858 struct stat statbuf; /* File information */
1859 char super[16], /* Super-type for filter */
1860 type[256], /* Type for filter */
1861 program[256], /* Program/filter name */
1862 pathprog[1024]; /* Complete path to program/filter */
1863 int cost; /* Cost of filter */
1864 const char *prefix; /* WARN/FAIL prefix */
1865
1866
1867 prefix = warn ? " WARN " : "**FAIL**";
1868
1869 for (attr = ppdFindAttr(ppd, "cupsFilter", NULL);
1870 attr;
1871 attr = ppdFindNextAttr(ppd, "cupsFilter", NULL))
1872 {
1873 if (!attr->value ||
1874 sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
1875 program) != 4)
1876 {
1877 if (!warn && !errors && !verbose)
1878 _cupsLangPuts(stdout, _(" FAIL\n"));
1879
1880 if (verbose >= 0)
1881 _cupsLangPrintf(stdout,
1882 _(" %s Bad cupsFilter value \"%s\"!\n"),
1883 prefix, attr->value ? attr->value : "");
1884
1885 if (!warn)
1886 errors ++;
1887 }
1888 else
1889 {
1890 if (program[0] == '/')
1891 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
1892 else
1893 {
1894 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
1895 ptr = CUPS_SERVERBIN;
1896
1897 if (*ptr == '/' || !*root)
1898 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
1899 program);
1900 else
1901 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
1902 program);
1903 }
1904
1905 if (stat(pathprog, &statbuf))
1906 {
1907 if (!warn && !errors && !verbose)
1908 _cupsLangPuts(stdout, _(" FAIL\n"));
1909
1910 if (verbose >= 0)
1911 _cupsLangPrintf(stdout, _(" %s Missing cupsFilter "
1912 "file \"%s\"\n"), prefix, program);
1913
1914 if (!warn)
1915 errors ++;
1916 }
1917 }
1918 }
1919
1920 for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
1921 attr;
1922 attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
1923 {
1924 if (!attr->value ||
1925 sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
1926 program) != 4)
1927 {
1928 if (!warn && !errors && !verbose)
1929 _cupsLangPuts(stdout, _(" FAIL\n"));
1930
1931 if (verbose >= 0)
1932 _cupsLangPrintf(stdout,
1933 _(" %s Bad cupsPreFilter value \"%s\"!\n"),
1934 prefix, attr->value ? attr->value : "");
1935
1936 if (!warn)
1937 errors ++;
1938 }
1939 else
1940 {
1941 if (program[0] == '/')
1942 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
1943 else
1944 {
1945 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
1946 ptr = CUPS_SERVERBIN;
1947
1948 if (*ptr == '/' || !*root)
1949 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
1950 program);
1951 else
1952 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
1953 program);
1954 }
1955
1956 if (stat(pathprog, &statbuf))
1957 {
1958 if (!warn && !errors && !verbose)
1959 _cupsLangPuts(stdout, _(" FAIL\n"));
1960
1961 if (verbose >= 0)
1962 _cupsLangPrintf(stdout, _(" %s Missing cupsPreFilter "
1963 "file \"%s\"\n"), prefix, program);
1964
1965 if (!warn)
1966 errors ++;
1967 }
1968 }
1969 }
1970
1971 return (errors);
1972}
1973
1974
1975/*
1976 * 'check_translations()' - Check translations in the PPD file.
1977 */
1978
3d8365b8 1979static int /* O - Errors found */
b94498cf 1980check_translations(ppd_file_t *ppd, /* I - PPD file */
1981 int errors, /* I - Errors found */
1982 int verbose, /* I - Verbosity level */
1983 int warn) /* I - Warnings only? */
1984{
1985 int j; /* Looping var */
1986 ppd_attr_t *attr; /* PPD attribute */
1987 char *languages, /* Copy of attribute value */
1988 *langstart, /* Start of current language */
1989 *langptr, /* Pointer into languages */
1990 keyword[PPD_MAX_NAME], /* Localization keyword (full) */
1991 llkeyword[PPD_MAX_NAME],/* Localization keyword (base) */
1992 ckeyword[PPD_MAX_NAME], /* Custom option keyword (full) */
1993 cllkeyword[PPD_MAX_NAME];
1994 /* Custom option keyword (base) */
1995 ppd_option_t *option; /* Standard UI option */
1996 ppd_coption_t *coption; /* Custom option */
1997 ppd_cparam_t *cparam; /* Custom parameter */
1998 cups_array_t *langlist; /* List of languages so far */
1999 char ll[3]; /* Base language */
2000 const char *prefix; /* WARN/FAIL prefix */
2001
2002
2003 prefix = warn ? " WARN " : "**FAIL**";
2004
2005 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
2006 attr->value)
2007 {
2008 /*
2009 * This file contains localizations, check them...
2010 */
2011
2012 languages = strdup(attr->value);
2013 langlist = cupsArrayNew((cups_array_func_t)strcmp, NULL);
2014
2015 for (langptr = languages; *langptr;)
2016 {
2017 /*
2018 * Skip leading whitespace...
2019 */
2020
2021 while (isspace(*langptr & 255))
2022 langptr ++;
2023
2024 if (!*langptr)
2025 break;
2026
2027 /*
2028 * Find the end of this language name...
2029 */
2030
2031 for (langstart = langptr;
2032 *langptr && !isspace(*langptr & 255);
2033 langptr ++);
2034
2035 if (*langptr)
2036 *langptr++ = '\0';
2037
2038 j = strlen(langstart);
2039 if (j != 2 && j != 5)
2040 {
2041 if (!warn && !errors && !verbose)
2042 _cupsLangPuts(stdout, _(" FAIL\n"));
2043
2044 if (verbose >= 0)
2045 _cupsLangPrintf(stdout,
2046 _(" %s Bad language \"%s\"!\n"),
2047 prefix, langstart);
2048
2049 if (!warn)
2050 errors ++;
2051
2052 continue;
2053 }
2054
2055 cupsArrayAdd(langlist, langstart);
2056
2057 strlcpy(ll, langstart, sizeof(ll));
2058
2059 /*
2060 * Loop through all options and choices...
2061 */
2062
2063 for (option = ppdFirstOption(ppd);
2064 option;
2065 option = ppdNextOption(ppd))
2066 {
09a101d6 2067 if (!strcmp(option->keyword, "PageRegion"))
2068 continue;
2069
b94498cf 2070 snprintf(keyword, sizeof(keyword), "%s.Translation", langstart);
2071 snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll);
2072
2073 if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL &&
2074 (attr = ppdFindAttr(ppd, llkeyword, option->keyword)) == NULL)
2075 {
2076 if (!warn && !errors && !verbose)
2077 _cupsLangPuts(stdout, _(" FAIL\n"));
2078
2079 if (verbose >= 0)
2080 _cupsLangPrintf(stdout,
2081 _(" %s Missing \"%s\" translation "
2082 "string for option %s!\n"),
2083 prefix, langstart, option->keyword);
2084
2085 if (!warn)
2086 errors ++;
2087 }
2088 else if (!valid_utf8(attr->text))
2089 {
2090 if (!warn && !errors && !verbose)
2091 _cupsLangPuts(stdout, _(" FAIL\n"));
2092
2093 if (verbose >= 0)
2094 _cupsLangPrintf(stdout,
2095 _(" %s Bad UTF-8 \"%s\" translation "
2096 "string for option %s!\n"),
2097 prefix, langstart, option->keyword);
2098
2099 if (!warn)
2100 errors ++;
2101 }
2102
2103 snprintf(keyword, sizeof(keyword), "%s.%s", langstart,
2104 option->keyword);
2105 snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll,
2106 option->keyword);
2107
2108 for (j = 0; j < option->num_choices; j ++)
2109 {
2110 if (!strcasecmp(option->choices[j].choice, "Custom") &&
2111 (coption = ppdFindCustomOption(ppd,
2112 option->keyword)) != NULL)
2113 {
2114 snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
2115 langstart, option->keyword);
2116
2117 if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
2118 !valid_utf8(attr->text))
2119 {
2120 if (!warn && !errors && !verbose)
2121 _cupsLangPuts(stdout, _(" FAIL\n"));
2122
2123 if (verbose >= 0)
2124 _cupsLangPrintf(stdout,
2125 _(" %s Bad UTF-8 \"%s\" "
2126 "translation string for option %s, "
2127 "choice %s!\n"),
2128 prefix, langstart,
2129 ckeyword + 1 + strlen(langstart),
2130 "True");
2131
2132 if (!warn)
2133 errors ++;
2134 }
2135
2136 if (strcasecmp(option->keyword, "PageSize"))
2137 {
2138 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
2139 cparam;
2140 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
2141 {
2142 snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
2143 langstart, option->keyword);
2144 snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s",
2145 ll, option->keyword);
2146
2147 if ((attr = ppdFindAttr(ppd, ckeyword,
2148 cparam->name)) == NULL &&
2149 (attr = ppdFindAttr(ppd, cllkeyword,
2150 cparam->name)) == NULL)
2151 {
2152 if (!warn && !errors && !verbose)
2153 _cupsLangPuts(stdout, _(" FAIL\n"));
2154
2155 if (verbose >= 0)
2156 _cupsLangPrintf(stdout,
2157 _(" %s Missing \"%s\" "
2158 "translation string for option %s, "
2159 "choice %s!\n"),
2160 prefix, langstart,
2161 ckeyword + 1 + strlen(langstart),
2162 cparam->name);
2163
2164 if (!warn)
2165 errors ++;
2166 }
2167 else if (!valid_utf8(attr->text))
2168 {
2169 if (!warn && !errors && !verbose)
2170 _cupsLangPuts(stdout, _(" FAIL\n"));
2171
2172 if (verbose >= 0)
2173 _cupsLangPrintf(stdout,
2174 _(" %s Bad UTF-8 \"%s\" "
2175 "translation string for option %s, "
2176 "choice %s!\n"),
2177 prefix, langstart,
2178 ckeyword + 1 + strlen(langstart),
2179 cparam->name);
2180
2181 if (!warn)
2182 errors ++;
2183 }
2184 }
2185 }
2186 }
2187 else if ((attr = ppdFindAttr(ppd, keyword,
2188 option->choices[j].choice)) == NULL &&
2189 (attr = ppdFindAttr(ppd, llkeyword,
2190 option->choices[j].choice)) == NULL)
2191 {
2192 if (!warn && !errors && !verbose)
2193 _cupsLangPuts(stdout, _(" FAIL\n"));
2194
2195 if (verbose >= 0)
2196 _cupsLangPrintf(stdout,
2197 _(" %s Missing \"%s\" "
2198 "translation string for option %s, "
2199 "choice %s!\n"),
2200 prefix, langstart, option->keyword,
2201 option->choices[j].choice);
2202
2203 if (!warn)
2204 errors ++;
2205 }
2206 else if (!valid_utf8(attr->text))
2207 {
2208 if (!warn && !errors && !verbose)
2209 _cupsLangPuts(stdout, _(" FAIL\n"));
2210
2211 if (verbose >= 0)
2212 _cupsLangPrintf(stdout,
2213 _(" %s Bad UTF-8 \"%s\" "
2214 "translation string for option %s, "
2215 "choice %s!\n"),
2216 prefix, langstart, option->keyword,
2217 option->choices[j].choice);
2218
2219 if (!warn)
2220 errors ++;
2221 }
2222 }
2223 }
2224 }
2225
2226 /*
2227 * Verify that we have the base language for each localized one...
2228 */
2229
2230 for (langptr = (char *)cupsArrayFirst(langlist);
2231 langptr;
2232 langptr = (char *)cupsArrayNext(langlist))
2233 if (langptr[2])
2234 {
2235 /*
2236 * Lookup the base language...
2237 */
2238
2239 cupsArraySave(langlist);
2240
2241 strlcpy(ll, langptr, sizeof(ll));
2242
2243 if (!cupsArrayFind(langlist, ll) && strcmp(ll, "zh"))
2244 {
2245 if (!warn && !errors && !verbose)
2246 _cupsLangPuts(stdout, _(" FAIL\n"));
2247
2248 if (verbose >= 0)
2249 _cupsLangPrintf(stdout,
2250 _(" %s No base translation \"%s\" "
2251 "is included in file!\n"), prefix, ll);
2252
2253 if (!warn)
2254 errors ++;
2255 }
2256
2257 cupsArrayRestore(langlist);
2258 }
2259
2260 /*
2261 * Free memory used for the languages...
2262 */
2263
2264 cupsArrayDelete(langlist);
2265 free(languages);
2266 }
2267
2268 return (errors);
2269}
2270
2271
ef416fc2 2272/*
2273 * 'show_conflicts()' - Show option conflicts in a PPD file.
2274 */
2275
3d8365b8 2276static void
ef416fc2 2277show_conflicts(ppd_file_t *ppd) /* I - PPD to check */
2278{
2279 int i, j; /* Looping variables */
2280 ppd_const_t *c; /* Current constraint */
2281 ppd_option_t *o1, *o2; /* Options */
2282 ppd_choice_t *c1, *c2; /* Choices */
2283
2284
2285 /*
2286 * Loop through all of the UI constraints and report any options
2287 * that conflict...
2288 */
2289
2290 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
2291 {
2292 /*
2293 * Grab pointers to the first option...
2294 */
2295
2296 o1 = ppdFindOption(ppd, c->option1);
2297
2298 if (o1 == NULL)
2299 continue;
2300 else if (c->choice1[0] != '\0')
2301 {
2302 /*
2303 * This constraint maps to a specific choice.
2304 */
2305
2306 c1 = ppdFindChoice(o1, c->choice1);
2307 }
2308 else
2309 {
2310 /*
2311 * This constraint applies to any choice for this option.
2312 */
2313
2314 for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
2315 if (c1->marked)
2316 break;
2317
2318 if (j == 0 ||
2319 !strcasecmp(c1->choice, "None") ||
2320 !strcasecmp(c1->choice, "Off") ||
2321 !strcasecmp(c1->choice, "False"))
2322 c1 = NULL;
2323 }
2324
2325 /*
2326 * Grab pointers to the second option...
2327 */
2328
2329 o2 = ppdFindOption(ppd, c->option2);
2330
2331 if (o2 == NULL)
2332 continue;
2333 else if (c->choice2[0] != '\0')
2334 {
2335 /*
2336 * This constraint maps to a specific choice.
2337 */
2338
2339 c2 = ppdFindChoice(o2, c->choice2);
2340 }
2341 else
2342 {
2343 /*
2344 * This constraint applies to any choice for this option.
2345 */
2346
2347 for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
2348 if (c2->marked)
2349 break;
2350
2351 if (j == 0 ||
2352 !strcasecmp(c2->choice, "None") ||
2353 !strcasecmp(c2->choice, "Off") ||
2354 !strcasecmp(c2->choice, "False"))
2355 c2 = NULL;
2356 }
2357
2358 /*
2359 * If both options are marked then there is a conflict...
2360 */
2361
2362 if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
fa73b229 2363 _cupsLangPrintf(stdout,
ef416fc2 2364 _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
2365 " (constraint=\"%s %s %s %s\")\n"),
2366 o1->keyword, c1->choice, o2->keyword, c2->choice,
2367 c->option1, c->choice1, c->option2, c->choice2);
2368 }
2369}
2370
2371
09a101d6 2372/*
2373 * 'test_raster()' - Test PostScript commands for raster printers.
2374 */
2375
2376static int /* O - 1 on success, 0 on failure */
2377test_raster(ppd_file_t *ppd, /* I - PPD file */
2378 int verbose) /* I - Verbosity */
2379{
2380 cups_page_header2_t header; /* Page header */
2381
2382
2383 ppdMarkDefaults(ppd);
2384 if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0))
2385 {
2386 if (!verbose)
2387 _cupsLangPuts(stdout, _(" FAIL\n"));
2388
2389 if (verbose >= 0)
2390 _cupsLangPrintf(stdout,
2391 _(" **FAIL** Default option code cannot be "
2392 "interpreted: %s\n"), cupsRasterErrorString());
2393
2394 return (0);
2395 }
2396 else
2397 return (1);
2398}
2399
2400
ef416fc2 2401/*
2402 * 'usage()' - Show program usage...
2403 */
2404
3d8365b8 2405static void
ef416fc2 2406usage(void)
2407{
fa73b229 2408 _cupsLangPuts(stdout,
b94498cf 2409 _("Usage: cupstestppd [options] filename1.ppd[.gz] "
2410 "[... filenameN.ppd[.gz]]\n"
2411 " program | cupstestppd [options] -\n"
2412 "\n"
2413 "Options:\n"
2414 "\n"
2415 " -R root-directory Set alternate root\n"
2416 " -W {all,none,constraints,defaults,filters,translations}\n"
2417 " Issue warnings instead of errors\n"
2418 " -q Run silently\n"
2419 " -r Use 'relaxed' open mode\n"
2420 " -v Be slightly verbose\n"
2421 " -vv Be very verbose\n"));
ef416fc2 2422
2423 exit(ERROR_USAGE);
2424}
2425
2426
2427/*
f7deaa1a 2428 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
2429 */
2430
3d8365b8 2431static int /* O - 1 if valid, 0 if not */
f7deaa1a 2432valid_utf8(const char *s) /* I - String to check */
2433{
2434 while (*s)
2435 {
2436 if (*s & 0x80)
2437 {
2438 /*
2439 * Check for valid UTF-8 sequence...
2440 */
2441
2442 if ((*s & 0xc0) == 0x80)
2443 return (0); /* Illegal suffix byte */
2444 else if ((*s & 0xe0) == 0xc0)
2445 {
2446 /*
2447 * 2-byte sequence...
2448 */
2449
2450 s ++;
2451
2452 if ((*s & 0xc0) != 0x80)
2453 return (0); /* Missing suffix byte */
2454 }
2455 else if ((*s & 0xf0) == 0xe0)
2456 {
2457 /*
2458 * 3-byte sequence...
2459 */
2460
2461 s ++;
2462
2463 if ((*s & 0xc0) != 0x80)
2464 return (0); /* Missing suffix byte */
2465
2466 s ++;
2467
2468 if ((*s & 0xc0) != 0x80)
2469 return (0); /* Missing suffix byte */
2470 }
2471 else if ((*s & 0xf8) == 0xf0)
2472 {
2473 /*
2474 * 4-byte sequence...
2475 */
2476
2477 s ++;
2478
2479 if ((*s & 0xc0) != 0x80)
2480 return (0); /* Missing suffix byte */
2481
2482 s ++;
2483
2484 if ((*s & 0xc0) != 0x80)
2485 return (0); /* Missing suffix byte */
2486
2487 s ++;
2488
2489 if ((*s & 0xc0) != 0x80)
2490 return (0); /* Missing suffix byte */
2491 }
2492 else
2493 return (0); /* Bad sequence */
2494 }
2495
2496 s ++;
2497 }
2498
2499 return (1);
2500}
2501
2502
2503/*
bc44d920 2504 * End of "$Id: cupstestppd.c 6649 2007-07-11 21:46:42Z mike $".
ef416fc2 2505 */