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