]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/cupstestppd.c
Update ipp documentation to reflect the behavior of configuring WiFi on IPP USB printers.
[thirdparty/cups.git] / systemv / cupstestppd.c
CommitLineData
ef416fc2 1/*
788d7a15 2 * PPD test program for CUPS.
ef416fc2 3 *
8e52928c 4 * THIS PROGRAM IS DEPRECATED AND WILL BE REMOVED IN A FUTURE VERSION OF CUPS.
ef416fc2 5 *
8e52928c
MS
6 * Copyright © 2007-2018 by Apple Inc.
7 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * Licensed under Apache License v2.0. See the file "LICENSE" for more
10 * information.
ef416fc2 11 *
788d7a15 12 * PostScript is a trademark of Adobe Systems, Inc.
ef416fc2 13 */
14
15/*
16 * Include necessary headers...
17 */
18
71e16022 19#include <cups/cups-private.h>
1340db2d 20#include <cups/dir.h>
a603edef 21#include <cups/ppd-private.h>
ac884b6a 22#include <cups/raster.h>
1340db2d 23#include <math.h>
24a06ed3 24#ifdef _WIN32
7a0cbd5e 25# define X_OK 0
24a06ed3 26#endif /* _WIN32 */
ef416fc2 27
28
b94498cf 29/*
30 * Error warning overrides...
31 */
32
33enum
34{
35 WARN_NONE = 0,
36 WARN_CONSTRAINTS = 1,
37 WARN_DEFAULTS = 2,
38 WARN_FILTERS = 4,
a603edef
MS
39 WARN_PROFILES = 8,
40 WARN_TRANSLATIONS = 16,
749b1e90 41 WARN_DUPLEX = 32,
1340db2d 42 WARN_SIZES = 64,
ef55b745
MS
43 WARN_FILENAME = 128,
44 WARN_ALL = 255
b94498cf 45};
46
47
ef416fc2 48/*
49 * Error codes...
50 */
51
fa73b229 52enum
53{
54 ERROR_NONE = 0,
55 ERROR_USAGE,
56 ERROR_FILE_OPEN,
57 ERROR_PPD_FORMAT,
58 ERROR_CONFORMANCE
59};
60
61
62/*
63 * Line endings...
64 */
65
66enum
67{
68 EOL_NONE = 0,
69 EOL_CR,
70 EOL_LF,
71 EOL_CRLF
72};
ef416fc2 73
74
b226ab99
MS
75/*
76 * File permissions...
77 */
78
79#define MODE_WRITE 0022 /* Group/other write */
80#define MODE_MASK 0555 /* Owner/group/other read+exec/search */
81#define MODE_DATAFILE 0444 /* Owner/group/other read */
82#define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
83#define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
84
85
ef416fc2 86/*
87 * Local functions...
88 */
89
3d8365b8 90static void check_basics(const char *filename);
91static int check_constraints(ppd_file_t *ppd, int errors, int verbose,
92 int warn);
749b1e90 93static int check_case(ppd_file_t *ppd, int errors, int verbose);
3d8365b8 94static int check_defaults(ppd_file_t *ppd, int errors, int verbose,
95 int warn);
749b1e90
MS
96static int check_duplex(ppd_file_t *ppd, int errors, int verbose,
97 int warn);
3d8365b8 98static int check_filters(ppd_file_t *ppd, const char *root, int errors,
99 int verbose, int warn);
a603edef
MS
100static int check_profiles(ppd_file_t *ppd, const char *root, int errors,
101 int verbose, int warn);
1340db2d
MS
102static int check_sizes(ppd_file_t *ppd, int errors, int verbose, int warn);
103static int check_translations(ppd_file_t *ppd, int errors, int verbose,
3d8365b8 104 int warn);
22c9029b 105static void show_conflicts(ppd_file_t *ppd, const char *prefix);
09a101d6 106static int test_raster(ppd_file_t *ppd, int verbose);
a32af27c 107static void usage(void) _CUPS_NORETURN;
1340db2d
MS
108static int valid_path(const char *keyword, const char *path, int errors,
109 int verbose, int warn);
3d8365b8 110static int valid_utf8(const char *s);
ef416fc2 111
b94498cf 112
ef416fc2 113/*
114 * 'main()' - Main entry for test program.
115 */
116
323c5de1 117int /* O - Exit status */
118main(int argc, /* I - Number of command-line args */
119 char *argv[]) /* I - Command-line arguments */
ef416fc2 120{
323c5de1 121 int i, j, k, m, n; /* Looping vars */
7e86f2f6 122 size_t len; /* Length of option name */
323c5de1 123 char *opt; /* Option character */
124 const char *ptr; /* Pointer into string */
82cc1f9a 125 cups_file_t *fp; /* PPD file */
323c5de1 126 int files; /* Number of files */
127 int verbose; /* Want verbose output? */
b94498cf 128 int warn; /* Which errors to just warn about */
b226ab99 129 int ignore; /* Which errors to ignore */
323c5de1 130 int status; /* Exit status */
131 int errors; /* Number of conformance errors */
132 int ppdversion; /* PPD spec version in PPD file */
133 ppd_status_t error; /* Status of ppdOpen*() */
134 int line; /* Line number for error */
a603edef 135 char *root; /* Root directory */
323c5de1 136 int xdpi, /* X resolution */
137 ydpi; /* Y resolution */
138 ppd_file_t *ppd; /* PPD file record */
139 ppd_attr_t *attr; /* PPD attribute */
140 ppd_size_t *size; /* Size record */
141 ppd_group_t *group; /* UI group */
142 ppd_option_t *option; /* Standard UI option */
143 ppd_group_t *group2; /* UI group */
144 ppd_option_t *option2; /* Standard UI option */
145 ppd_choice_t *choice; /* Standard UI option choice */
dd1abb6b 146 struct lconv *loc; /* Locale data */
ef416fc2 147 static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
148 static char *sections[] = { "ANY", "DOCUMENT", "EXIT",
149 "JCL", "PAGE", "PROLOG" };
150
151
07725fee 152 _cupsSetLocale(argv);
dd1abb6b 153 loc = localeconv();
d09495fa 154
ef416fc2 155 /*
156 * Display PPD files for each file listed on the command-line...
157 */
158
159 ppdSetConformance(PPD_CONFORM_STRICT);
160
161 verbose = 0;
162 ppd = NULL;
163 files = 0;
164 status = ERROR_NONE;
323c5de1 165 root = "";
b94498cf 166 warn = WARN_NONE;
b226ab99 167 ignore = WARN_NONE;
ef416fc2 168
169 for (i = 1; i < argc; i ++)
8e52928c
MS
170 if (!strcmp(argv[i], "--help"))
171 usage();
172 else if (argv[i][0] == '-' && argv[i][1])
ef416fc2 173 {
174 for (opt = argv[i] + 1; *opt; opt ++)
175 switch (*opt)
176 {
b226ab99
MS
177 case 'I' : /* Ignore errors */
178 i ++;
179
180 if (i >= argc)
181 usage();
182
183 if (!strcmp(argv[i], "none"))
184 ignore = WARN_NONE;
ef55b745
MS
185 else if (!strcmp(argv[i], "filename"))
186 ignore |= WARN_FILENAME;
b226ab99
MS
187 else if (!strcmp(argv[i], "filters"))
188 ignore |= WARN_FILTERS;
189 else if (!strcmp(argv[i], "profiles"))
190 ignore |= WARN_PROFILES;
191 else if (!strcmp(argv[i], "all"))
192 ignore = WARN_FILTERS | WARN_PROFILES;
193 else
194 usage();
195 break;
196
323c5de1 197 case 'R' : /* Alternate root directory */
198 i ++;
199
200 if (i >= argc)
201 usage();
202
203 root = argv[i];
204 break;
205
b226ab99 206 case 'W' : /* Turn errors into warnings */
b94498cf 207 i ++;
208
209 if (i >= argc)
210 usage();
211
212 if (!strcmp(argv[i], "none"))
213 warn = WARN_NONE;
214 else if (!strcmp(argv[i], "constraints"))
215 warn |= WARN_CONSTRAINTS;
216 else if (!strcmp(argv[i], "defaults"))
217 warn |= WARN_DEFAULTS;
749b1e90
MS
218 else if (!strcmp(argv[i], "duplex"))
219 warn |= WARN_DUPLEX;
b94498cf 220 else if (!strcmp(argv[i], "filters"))
221 warn |= WARN_FILTERS;
a603edef
MS
222 else if (!strcmp(argv[i], "profiles"))
223 warn |= WARN_PROFILES;
1340db2d
MS
224 else if (!strcmp(argv[i], "sizes"))
225 warn |= WARN_SIZES;
b94498cf 226 else if (!strcmp(argv[i], "translations"))
227 warn |= WARN_TRANSLATIONS;
228 else if (!strcmp(argv[i], "all"))
229 warn = WARN_ALL;
230 else
231 usage();
232 break;
233
ef416fc2 234 case 'q' : /* Quiet mode */
235 if (verbose > 0)
236 {
fa73b229 237 _cupsLangPuts(stderr,
ef416fc2 238 _("cupstestppd: The -q option is incompatible "
0837b7e8 239 "with the -v option."));
ef416fc2 240 return (1);
241 }
242
243 verbose --;
244 break;
245
246 case 'r' : /* Relaxed mode */
247 ppdSetConformance(PPD_CONFORM_RELAXED);
248 break;
249
250 case 'v' : /* Verbose mode */
251 if (verbose < 0)
252 {
fa73b229 253 _cupsLangPuts(stderr,
ef416fc2 254 _("cupstestppd: The -v option is incompatible "
0837b7e8 255 "with the -q option."));
ef416fc2 256 return (1);
257 }
258
259 verbose ++;
260 break;
261
262 default :
263 usage();
ef416fc2 264 }
265 }
266 else
267 {
268 /*
269 * Open the PPD file...
270 */
271
272 if (files && verbose >= 0)
0837b7e8 273 puts("");
ef416fc2 274
275 files ++;
276
277 if (argv[i][0] == '-')
278 {
279 /*
280 * Read from stdin...
281 */
282
82cc1f9a 283 ppd = _ppdOpen(cupsFileStdin(), _PPD_LOCALIZATION_ALL);
bdd6c45b
MS
284
285 if (verbose >= 0)
286 printf("%s:", (ppd && ppd->pcfilename) ? ppd->pcfilename : "(stdin)");
ef416fc2 287 }
288 else
289 {
290 /*
291 * Read from a file...
292 */
293
294 if (verbose >= 0)
295 printf("%s:", argv[i]);
296
82cc1f9a
MS
297 if ((fp = cupsFileOpen(argv[i], "r")) != NULL)
298 {
299 ppd = _ppdOpen(fp, _PPD_LOCALIZATION_ALL);
300 cupsFileClose(fp);
301 }
302 else
303 {
304 status = ERROR_FILE_OPEN;
305
306 if (verbose >= 0)
307 {
308 _cupsLangPuts(stdout, _(" FAIL"));
309 _cupsLangPrintf(stdout,
f3c17241
MS
310 _(" **FAIL** Unable to open PPD file - %s on "
311 "line %d."), strerror(errno), 0);
82cc1f9a
MS
312 continue;
313 }
314 }
ef416fc2 315 }
316
317 if (ppd == NULL)
318 {
319 error = ppdLastError(&line);
320
321 if (error <= PPD_ALLOC_ERROR)
322 {
323 status = ERROR_FILE_OPEN;
324
325 if (verbose >= 0)
84315f46
MS
326 {
327 _cupsLangPuts(stdout, _(" FAIL"));
fa73b229 328 _cupsLangPrintf(stdout,
f3c17241
MS
329 _(" **FAIL** Unable to open PPD file - %s on "
330 "line %d."), strerror(errno), 0);
84315f46 331 }
ef416fc2 332 }
333 else
334 {
335 status = ERROR_PPD_FORMAT;
336
337 if (verbose >= 0)
84315f46
MS
338 {
339 _cupsLangPuts(stdout, _(" FAIL"));
fa73b229 340 _cupsLangPrintf(stdout,
84315f46 341 _(" **FAIL** Unable to open PPD file - "
0837b7e8 342 "%s on line %d."),
ef416fc2 343 ppdErrorString(error), line);
344
345 switch (error)
346 {
347 case PPD_MISSING_PPDADOBE4 :
fa73b229 348 _cupsLangPuts(stdout,
0837b7e8
MS
349 _(" REF: Page 42, section "
350 "5.2."));
ef416fc2 351 break;
352 case PPD_MISSING_VALUE :
fa73b229 353 _cupsLangPuts(stdout,
0837b7e8
MS
354 _(" REF: Page 20, section "
355 "3.4."));
ef416fc2 356 break;
357 case PPD_BAD_OPEN_GROUP :
358 case PPD_NESTED_OPEN_GROUP :
fa73b229 359 _cupsLangPuts(stdout,
0837b7e8
MS
360 _(" REF: Pages 45-46, section "
361 "5.2."));
ef416fc2 362 break;
363 case PPD_BAD_OPEN_UI :
364 case PPD_NESTED_OPEN_UI :
fa73b229 365 _cupsLangPuts(stdout,
0837b7e8
MS
366 _(" REF: Pages 42-45, section "
367 "5.2."));
ef416fc2 368 break;
369 case PPD_BAD_ORDER_DEPENDENCY :
fa73b229 370 _cupsLangPuts(stdout,
0837b7e8
MS
371 _(" REF: Pages 48-49, section "
372 "5.2."));
ef416fc2 373 break;
374 case PPD_BAD_UI_CONSTRAINTS :
fa73b229 375 _cupsLangPuts(stdout,
0837b7e8
MS
376 _(" REF: Pages 52-54, section "
377 "5.2."));
ef416fc2 378 break;
379 case PPD_MISSING_ASTERISK :
fa73b229 380 _cupsLangPuts(stdout,
0837b7e8
MS
381 _(" REF: Page 15, section "
382 "3.2."));
ef416fc2 383 break;
384 case PPD_LINE_TOO_LONG :
fa73b229 385 _cupsLangPuts(stdout,
0837b7e8
MS
386 _(" REF: Page 15, section "
387 "3.1."));
ef416fc2 388 break;
389 case PPD_ILLEGAL_CHARACTER :
fa73b229 390 _cupsLangPuts(stdout,
0837b7e8
MS
391 _(" REF: Page 15, section "
392 "3.1."));
ef416fc2 393 break;
394 case PPD_ILLEGAL_MAIN_KEYWORD :
fa73b229 395 _cupsLangPuts(stdout,
0837b7e8
MS
396 _(" REF: Pages 16-17, section "
397 "3.2."));
ef416fc2 398 break;
399 case PPD_ILLEGAL_OPTION_KEYWORD :
fa73b229 400 _cupsLangPuts(stdout,
0837b7e8
MS
401 _(" REF: Page 19, section "
402 "3.3."));
ef416fc2 403 break;
404 case PPD_ILLEGAL_TRANSLATION :
fa73b229 405 _cupsLangPuts(stdout,
0837b7e8
MS
406 _(" REF: Page 27, section "
407 "3.5."));
ef416fc2 408 break;
409 default :
410 break;
411 }
fa73b229 412
413 check_basics(argv[i]);
ef416fc2 414 }
415 }
416
417 continue;
418 }
419
420 /*
421 * Show the header and then perform basic conformance tests (limited
422 * only by what the CUPS PPD functions actually load...)
423 */
424
425 errors = 0;
426 ppdversion = 43;
427
428 if (verbose > 0)
fa73b229 429 _cupsLangPuts(stdout,
0837b7e8 430 _("\n DETAILED CONFORMANCE TEST RESULTS"));
ef416fc2 431
432 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
433 attr->value)
dd1abb6b 434 ppdversion = (int)(10 * _cupsStrScand(attr->value, NULL, loc) + 0.5);
ef416fc2 435
a4845881
MS
436 if ((attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL)
437 {
438 do
439 {
440 if (strstr(attr->value, "application/vnd.cups-raster"))
441 {
442 if (!test_raster(ppd, verbose))
443 errors ++;
444 break;
445 }
09a101d6 446 }
a4845881
MS
447 while ((attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL)) != NULL);
448 }
449 else
450 {
451 for (j = 0; j < ppd->num_filters; j ++)
452 if (strstr(ppd->filters[j], "application/vnd.cups-raster"))
453 {
454 if (!test_raster(ppd, verbose))
455 errors ++;
456 break;
457 }
458 }
09a101d6 459
b423cd4c 460 /*
461 * Look for default keywords with no matching option...
462 */
463
b94498cf 464 if (!(warn & WARN_DEFAULTS))
465 errors = check_defaults(ppd, errors, verbose, 0);
ef416fc2 466
467 if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
468 {
469 if (verbose >= 0)
470 {
471 if (!errors && !verbose)
0837b7e8 472 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 473
fa73b229 474 _cupsLangPuts(stdout,
b94498cf 475 _(" **FAIL** REQUIRED DefaultImageableArea\n"
0837b7e8 476 " REF: Page 102, section 5.15."));
b94498cf 477 }
ef416fc2 478
479 errors ++;
480 }
481 else if (ppdPageSize(ppd, attr->value) == NULL &&
b94498cf 482 strcmp(attr->value, "Unknown"))
ef416fc2 483 {
484 if (verbose >= 0)
485 {
486 if (!errors && !verbose)
0837b7e8 487 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 488
fa73b229 489 _cupsLangPrintf(stdout,
f3c17241 490 _(" **FAIL** Bad DefaultImageableArea %s\n"
0837b7e8 491 " REF: Page 102, section 5.15."),
ef416fc2 492 attr->value);
b94498cf 493 }
ef416fc2 494
495 errors ++;
496 }
497 else
498 {
499 if (verbose > 0)
0837b7e8 500 _cupsLangPuts(stdout, _(" PASS DefaultImageableArea"));
ef416fc2 501 }
502
503 if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL)
504 {
505 if (verbose >= 0)
506 {
507 if (!errors && !verbose)
0837b7e8 508 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 509
fa73b229 510 _cupsLangPuts(stdout,
b94498cf 511 _(" **FAIL** REQUIRED DefaultPaperDimension\n"
0837b7e8 512 " REF: Page 103, section 5.15."));
b94498cf 513 }
ef416fc2 514
515 errors ++;
516 }
517 else if (ppdPageSize(ppd, attr->value) == NULL &&
b94498cf 518 strcmp(attr->value, "Unknown"))
ef416fc2 519 {
520 if (verbose >= 0)
521 {
522 if (!errors && !verbose)
0837b7e8 523 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 524
fa73b229 525 _cupsLangPrintf(stdout,
f3c17241 526 _(" **FAIL** Bad DefaultPaperDimension %s\n"
0837b7e8 527 " REF: Page 103, section 5.15."),
ef416fc2 528 attr->value);
b94498cf 529 }
ef416fc2 530
531 errors ++;
532 }
533 else if (verbose > 0)
0837b7e8 534 _cupsLangPuts(stdout, _(" PASS DefaultPaperDimension"));
ef416fc2 535
536 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
0837b7e8
MS
537 for (k = 0, option = group->options;
538 k < group->num_options;
539 k ++, option ++)
ef416fc2 540 {
541 /*
542 * Verify that we have a default choice...
543 */
544
545 if (option->defchoice[0])
546 {
b94498cf 547 if (ppdFindChoice(option, option->defchoice) == NULL &&
548 strcmp(option->defchoice, "Unknown"))
ef416fc2 549 {
550 if (verbose >= 0)
551 {
552 if (!errors && !verbose)
0837b7e8 553 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 554
fa73b229 555 _cupsLangPrintf(stdout,
f3c17241 556 _(" **FAIL** Bad Default%s %s\n"
0837b7e8 557 " REF: Page 40, section 4.5."),
ef416fc2 558 option->keyword, option->defchoice);
b94498cf 559 }
ef416fc2 560
561 errors ++;
562 }
563 else if (verbose > 0)
fa73b229 564 _cupsLangPrintf(stdout,
0837b7e8 565 _(" PASS Default%s"),
ef416fc2 566 option->keyword);
567 }
568 else
569 {
570 if (verbose >= 0)
571 {
572 if (!errors && !verbose)
0837b7e8 573 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 574
fa73b229 575 _cupsLangPrintf(stdout,
b94498cf 576 _(" **FAIL** REQUIRED Default%s\n"
0837b7e8 577 " REF: Page 40, section 4.5."),
b94498cf 578 option->keyword);
579 }
ef416fc2 580
581 errors ++;
582 }
583 }
584
557dde9f 585 if ((attr = ppdFindAttr(ppd, "FileVersion", NULL)) != NULL)
ef416fc2 586 {
557dde9f
MS
587 for (ptr = attr->value; *ptr; ptr ++)
588 if (!isdigit(*ptr & 255) && *ptr != '.')
589 break;
590
591 if (*ptr)
592 {
593 if (verbose >= 0)
594 {
595 if (!errors && !verbose)
0837b7e8 596 _cupsLangPuts(stdout, _(" FAIL"));
557dde9f
MS
597
598 _cupsLangPrintf(stdout,
599 _(" **FAIL** Bad FileVersion \"%s\"\n"
0837b7e8 600 " REF: Page 56, section 5.3."),
557dde9f
MS
601 attr->value);
602 }
603
604 errors ++;
605 }
606 else if (verbose > 0)
0837b7e8 607 _cupsLangPuts(stdout, _(" PASS FileVersion"));
ef416fc2 608 }
609 else
610 {
611 if (verbose >= 0)
612 {
613 if (!errors && !verbose)
0837b7e8 614 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 615
fa73b229 616 _cupsLangPuts(stdout,
ef416fc2 617 _(" **FAIL** REQUIRED FileVersion\n"
0837b7e8 618 " REF: Page 56, section 5.3."));
ef416fc2 619 }
620
621 errors ++;
622 }
623
557dde9f 624 if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL)
ef416fc2 625 {
557dde9f
MS
626 ptr = attr->value;
627 if (*ptr == '4' && ptr[1] == '.')
628 {
88f9aafc 629
557dde9f
MS
630 for (ptr += 2; *ptr; ptr ++)
631 if (!isdigit(*ptr & 255))
632 break;
633 }
634
635 if (*ptr)
636 {
637 if (verbose >= 0)
638 {
639 if (!errors && !verbose)
0837b7e8 640 _cupsLangPuts(stdout, _(" FAIL"));
557dde9f
MS
641
642 _cupsLangPrintf(stdout,
643 _(" **FAIL** Bad FormatVersion \"%s\"\n"
0837b7e8 644 " REF: Page 56, section 5.3."),
557dde9f
MS
645 attr->value);
646 }
647
648 errors ++;
649 }
650 else if (verbose > 0)
0837b7e8 651 _cupsLangPuts(stdout, _(" PASS FormatVersion"));
ef416fc2 652 }
653 else
654 {
655 if (verbose >= 0)
656 {
657 if (!errors && !verbose)
0837b7e8 658 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 659
fa73b229 660 _cupsLangPuts(stdout,
ef416fc2 661 _(" **FAIL** REQUIRED FormatVersion\n"
0837b7e8 662 " REF: Page 56, section 5.3."));
ef416fc2 663 }
664
665 errors ++;
666 }
667
668 if (ppd->lang_encoding != NULL)
669 {
670 if (verbose > 0)
0837b7e8 671 _cupsLangPuts(stdout, _(" PASS LanguageEncoding"));
ef416fc2 672 }
673 else if (ppdversion > 40)
674 {
675 if (verbose >= 0)
676 {
677 if (!errors && !verbose)
0837b7e8 678 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 679
fa73b229 680 _cupsLangPuts(stdout,
ef416fc2 681 _(" **FAIL** REQUIRED LanguageEncoding\n"
0837b7e8 682 " REF: Pages 56-57, section 5.3."));
ef416fc2 683 }
684
685 errors ++;
686 }
687
688 if (ppd->lang_version != NULL)
689 {
690 if (verbose > 0)
0837b7e8 691 _cupsLangPuts(stdout, _(" PASS LanguageVersion"));
ef416fc2 692 }
693 else
694 {
695 if (verbose >= 0)
696 {
697 if (!errors && !verbose)
0837b7e8 698 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 699
fa73b229 700 _cupsLangPuts(stdout,
ef416fc2 701 _(" **FAIL** REQUIRED LanguageVersion\n"
0837b7e8 702 " REF: Pages 57-58, section 5.3."));
ef416fc2 703 }
704
705 errors ++;
706 }
707
708 if (ppd->manufacturer != NULL)
709 {
88f9aafc
MS
710 if (!_cups_strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) ||
711 !_cups_strncasecmp(ppd->manufacturer, "Hewlett Packard", 15))
ef416fc2 712 {
713 if (verbose >= 0)
714 {
715 if (!errors && !verbose)
0837b7e8 716 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 717
f3c17241
MS
718 _cupsLangPrintf(stdout,
719 _(" **FAIL** Bad Manufacturer (should be "
720 "\"%s\")\n"
721 " REF: Page 211, table D.1."),
722 "HP");
ef416fc2 723 }
724
725 errors ++;
726 }
88f9aafc
MS
727 else if (!_cups_strncasecmp(ppd->manufacturer, "OkiData", 7) ||
728 !_cups_strncasecmp(ppd->manufacturer, "Oki Data", 8))
b94498cf 729 {
730 if (verbose >= 0)
731 {
732 if (!errors && !verbose)
0837b7e8 733 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 734
f3c17241
MS
735 _cupsLangPrintf(stdout,
736 _(" **FAIL** Bad Manufacturer (should be "
737 "\"%s\")\n"
738 " REF: Page 211, table D.1."),
739 "Oki");
b94498cf 740 }
741
742 errors ++;
743 }
ef416fc2 744 else if (verbose > 0)
0837b7e8 745 _cupsLangPuts(stdout, _(" PASS Manufacturer"));
ef416fc2 746 }
747 else if (ppdversion >= 43)
748 {
749 if (verbose >= 0)
750 {
751 if (!errors && !verbose)
0837b7e8 752 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 753
fa73b229 754 _cupsLangPuts(stdout,
ef416fc2 755 _(" **FAIL** REQUIRED Manufacturer\n"
0837b7e8 756 " REF: Pages 58-59, section 5.3."));
ef416fc2 757 }
758
759 errors ++;
760 }
761
762 if (ppd->modelname != NULL)
763 {
764 for (ptr = ppd->modelname; *ptr; ptr ++)
765 if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr))
766 break;
767
768 if (*ptr)
769 {
770 if (verbose >= 0)
771 {
772 if (!errors && !verbose)
0837b7e8 773 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 774
fa73b229 775 _cupsLangPrintf(stdout,
f3c17241 776 _(" **FAIL** Bad ModelName - \"%c\" not "
ef416fc2 777 "allowed in string.\n"
0837b7e8 778 " REF: Pages 59-60, section 5.3."),
ef416fc2 779 *ptr);
780 }
781
782 errors ++;
783 }
784 else if (verbose > 0)
0837b7e8 785 _cupsLangPuts(stdout, _(" PASS ModelName"));
ef416fc2 786 }
787 else
788 {
789 if (verbose >= 0)
790 {
791 if (!errors && !verbose)
0837b7e8 792 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 793
fa73b229 794 _cupsLangPuts(stdout,
ef416fc2 795 _(" **FAIL** REQUIRED ModelName\n"
0837b7e8 796 " REF: Pages 59-60, section 5.3."));
ef416fc2 797 }
798
799 errors ++;
800 }
801
802 if (ppd->nickname != NULL)
803 {
804 if (verbose > 0)
0837b7e8 805 _cupsLangPuts(stdout, _(" PASS NickName"));
ef416fc2 806 }
807 else
808 {
809 if (verbose >= 0)
810 {
811 if (!errors && !verbose)
0837b7e8 812 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 813
fa73b229 814 _cupsLangPuts(stdout,
ef416fc2 815 _(" **FAIL** REQUIRED NickName\n"
0837b7e8 816 " REF: Page 60, section 5.3."));
ef416fc2 817 }
818
819 errors ++;
820 }
821
822 if (ppdFindOption(ppd, "PageSize") != NULL)
823 {
824 if (verbose > 0)
0837b7e8 825 _cupsLangPuts(stdout, _(" PASS PageSize"));
ef416fc2 826 }
827 else
828 {
829 if (verbose >= 0)
830 {
831 if (!errors && !verbose)
0837b7e8 832 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 833
fa73b229 834 _cupsLangPuts(stdout,
ef416fc2 835 _(" **FAIL** REQUIRED PageSize\n"
0837b7e8 836 " REF: Pages 99-100, section 5.14."));
ef416fc2 837 }
838
839 errors ++;
840 }
841
842 if (ppdFindOption(ppd, "PageRegion") != NULL)
843 {
844 if (verbose > 0)
0837b7e8 845 _cupsLangPuts(stdout, _(" PASS PageRegion"));
ef416fc2 846 }
847 else
848 {
849 if (verbose >= 0)
850 {
851 if (!errors && !verbose)
0837b7e8 852 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 853
fa73b229 854 _cupsLangPuts(stdout,
ef416fc2 855 _(" **FAIL** REQUIRED PageRegion\n"
0837b7e8 856 " REF: Page 100, section 5.14."));
ef416fc2 857 }
858
859 errors ++;
860 }
861
862 if (ppd->pcfilename != NULL)
863 {
864 if (verbose > 0)
0837b7e8 865 _cupsLangPuts(stdout, _(" PASS PCFileName"));
ef416fc2 866 }
ef55b745 867 else if (!(ignore & WARN_FILENAME))
ef416fc2 868 {
869 if (verbose >= 0)
870 {
871 if (!errors && !verbose)
0837b7e8 872 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 873
fa73b229 874 _cupsLangPuts(stdout,
ef416fc2 875 _(" **FAIL** REQUIRED PCFileName\n"
0837b7e8 876 " REF: Pages 61-62, section 5.3."));
ef416fc2 877 }
878
879 errors ++;
880 }
881
882 if (ppd->product != NULL)
883 {
884 if (ppd->product[0] != '(' ||
885 ppd->product[strlen(ppd->product) - 1] != ')')
886 {
887 if (verbose >= 0)
888 {
889 if (!errors && !verbose)
0837b7e8 890 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 891
fa73b229 892 _cupsLangPuts(stdout,
f3c17241 893 _(" **FAIL** Bad Product - not \"(string)\".\n"
0837b7e8 894 " REF: Page 62, section 5.3."));
ef416fc2 895 }
896
897 errors ++;
898 }
899 else if (verbose > 0)
0837b7e8 900 _cupsLangPuts(stdout, _(" PASS Product"));
ef416fc2 901 }
902 else
903 {
904 if (verbose >= 0)
905 {
906 if (!errors && !verbose)
0837b7e8 907 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 908
fa73b229 909 _cupsLangPuts(stdout,
ef416fc2 910 _(" **FAIL** REQUIRED Product\n"
0837b7e8 911 " REF: Page 62, section 5.3."));
ef416fc2 912 }
913
914 errors ++;
915 }
916
917 if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL &&
918 attr->value != NULL)
919 {
920 char junkstr[255]; /* Temp string */
921 int junkint; /* Temp integer */
922
923
95633d62 924 if (sscanf(attr->value, "(%254[^)\n])%d", junkstr, &junkint) != 2)
ef416fc2 925 {
926 if (verbose >= 0)
927 {
928 if (!errors && !verbose)
0837b7e8 929 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 930
fa73b229 931 _cupsLangPuts(stdout,
f3c17241 932 _(" **FAIL** Bad PSVersion - not \"(string) "
ef416fc2 933 "int\".\n"
0837b7e8 934 " REF: Pages 62-64, section 5.3."));
ef416fc2 935 }
936
937 errors ++;
938 }
939 else if (verbose > 0)
0837b7e8 940 _cupsLangPuts(stdout, _(" PASS PSVersion"));
ef416fc2 941 }
942 else
943 {
944 if (verbose >= 0)
945 {
946 if (!errors && !verbose)
0837b7e8 947 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 948
fa73b229 949 _cupsLangPuts(stdout,
ef416fc2 950 _(" **FAIL** REQUIRED PSVersion\n"
0837b7e8 951 " REF: Pages 62-64, section 5.3."));
ef416fc2 952 }
953
954 errors ++;
955 }
956
957 if (ppd->shortnickname != NULL)
958 {
959 if (strlen(ppd->shortnickname) > 31)
960 {
961 if (verbose >= 0)
962 {
963 if (!errors && !verbose)
0837b7e8 964 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 965
fa73b229 966 _cupsLangPuts(stdout,
f3c17241 967 _(" **FAIL** Bad ShortNickName - longer "
ef416fc2 968 "than 31 chars.\n"
0837b7e8 969 " REF: Pages 64-65, section 5.3."));
ef416fc2 970 }
971
972 errors ++;
973 }
974 else if (verbose > 0)
0837b7e8 975 _cupsLangPuts(stdout, _(" PASS ShortNickName"));
ef416fc2 976 }
977 else if (ppdversion >= 43)
978 {
979 if (verbose >= 0)
980 {
981 if (!errors && !verbose)
0837b7e8 982 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 983
fa73b229 984 _cupsLangPuts(stdout,
ef416fc2 985 _(" **FAIL** REQUIRED ShortNickName\n"
0837b7e8 986 " REF: Page 64-65, section 5.3."));
ef416fc2 987 }
988
989 errors ++;
990 }
991
992 if (ppd->patches != NULL && strchr(ppd->patches, '\"') &&
993 strstr(ppd->patches, "*End"))
994 {
995 if (verbose >= 0)
996 {
997 if (!errors && !verbose)
0837b7e8 998 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 999
fa73b229 1000 _cupsLangPuts(stdout,
f3c17241 1001 _(" **FAIL** Bad JobPatchFile attribute in file\n"
0837b7e8 1002 " REF: Page 24, section 3.4."));
ef416fc2 1003 }
1004
1005 errors ++;
1006 }
1007
1008 /*
1009 * Check for page sizes without the corresponding ImageableArea or
1010 * PaperDimension values...
1011 */
1012
1013 if (ppd->num_sizes == 0)
1014 {
1015 if (verbose >= 0)
1016 {
1017 if (!errors && !verbose)
0837b7e8 1018 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 1019
fa73b229 1020 _cupsLangPuts(stdout,
ef416fc2 1021 _(" **FAIL** REQUIRED PageSize\n"
1022 " REF: Page 41, section 5.\n"
0837b7e8 1023 " REF: Page 99, section 5.14."));
ef416fc2 1024 }
1025
1026 errors ++;
1027 }
1028 else
1029 {
1030 for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++)
1031 {
1032 /*
1033 * Don't check custom size...
1034 */
1035
1036 if (!strcmp(size->name, "Custom"))
1037 continue;
1038
1039 /*
1040 * Check for ImageableArea...
1041 */
1042
1043 if (size->left == 0.0 && size->bottom == 0.0 &&
1044 size->right == 0.0 && size->top == 0.0)
1045 {
1046 if (verbose >= 0)
1047 {
1048 if (!errors && !verbose)
0837b7e8 1049 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 1050
fa73b229 1051 _cupsLangPrintf(stdout,
ef416fc2 1052 _(" **FAIL** REQUIRED ImageableArea for "
1053 "PageSize %s\n"
1054 " REF: Page 41, section 5.\n"
0837b7e8 1055 " REF: Page 102, section 5.15."),
ef416fc2 1056 size->name);
1057 }
1058
1059 errors ++;
1060 }
1061
1062 /*
1063 * Check for PaperDimension...
1064 */
1065
82cc1f9a 1066 if (size->width <= 0.0 && size->length <= 0.0)
ef416fc2 1067 {
1068 if (verbose >= 0)
1069 {
1070 if (!errors && !verbose)
0837b7e8 1071 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 1072
fa73b229 1073 _cupsLangPrintf(stdout,
ef416fc2 1074 _(" **FAIL** REQUIRED PaperDimension "
1075 "for PageSize %s\n"
1076 " REF: Page 41, section 5.\n"
0837b7e8 1077 " REF: Page 103, section 5.15."),
ef416fc2 1078 size->name);
1079 }
1080
1081 errors ++;
1082 }
1083 }
1084 }
1085
1086 /*
1087 * Check for valid Resolution, JCLResolution, or SetResolution values...
1088 */
1089
1090 if ((option = ppdFindOption(ppd, "Resolution")) == NULL)
1091 if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL)
1092 option = ppdFindOption(ppd, "SetResolution");
1093
1094 if (option != NULL)
1095 {
0837b7e8
MS
1096 for (j = option->num_choices, choice = option->choices;
1097 j > 0;
1098 j --, choice ++)
ef416fc2 1099 {
1100 /*
1101 * Verify that all resolution options are of the form NNNdpi
1102 * or NNNxNNNdpi...
1103 */
1104
1105 xdpi = strtol(choice->choice, (char **)&ptr, 10);
1106 if (ptr > choice->choice && xdpi > 0)
1107 {
1108 if (*ptr == 'x')
1109 ydpi = strtol(ptr + 1, (char **)&ptr, 10);
1110 else
1111 ydpi = xdpi;
1112 }
1113 else
1114 ydpi = xdpi;
1115
db1f069b
MS
1116 if (xdpi <= 0 || xdpi > 99999 || ydpi <= 0 || ydpi > 99999 ||
1117 strcmp(ptr, "dpi"))
ef416fc2 1118 {
1119 if (verbose >= 0)
1120 {
1121 if (!errors && !verbose)
0837b7e8 1122 _cupsLangPuts(stdout, _(" FAIL"));
ef416fc2 1123
fa73b229 1124 _cupsLangPrintf(stdout,
f3c17241 1125 _(" **FAIL** Bad option %s choice %s\n"
0837b7e8 1126 " REF: Page 84, section 5.9"),
ef416fc2 1127 option->keyword, choice->choice);
1128 }
1129
1130 errors ++;
1131 }
1132 }
1133 }
1134
b94498cf 1135 if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
1136 strcmp(attr->name, "1284DeviceID"))
b423cd4c 1137 {
b94498cf 1138 if (verbose >= 0)
1139 {
1140 if (!errors && !verbose)
0837b7e8 1141 _cupsLangPuts(stdout, _(" FAIL"));
b423cd4c 1142
b94498cf 1143 _cupsLangPrintf(stdout,
4d301e69 1144 _(" **FAIL** %s must be 1284DeviceID\n"
0837b7e8 1145 " REF: Page 72, section 5.5"),
b94498cf 1146 attr->name);
1147 }
b423cd4c 1148
b94498cf 1149 errors ++;
1150 }
b423cd4c 1151
749b1e90
MS
1152 errors = check_case(ppd, errors, verbose);
1153
b94498cf 1154 if (!(warn & WARN_CONSTRAINTS))
1155 errors = check_constraints(ppd, errors, verbose, 0);
c0e1af83 1156
b226ab99 1157 if (!(warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
b94498cf 1158 errors = check_filters(ppd, root, errors, verbose, 0);
b423cd4c 1159
b226ab99 1160 if (!(warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
a603edef
MS
1161 errors = check_profiles(ppd, root, errors, verbose, 0);
1162
1340db2d
MS
1163 if (!(warn & WARN_SIZES))
1164 errors = check_sizes(ppd, errors, verbose, 0);
1165
b94498cf 1166 if (!(warn & WARN_TRANSLATIONS))
1167 errors = check_translations(ppd, errors, verbose, 0);
b423cd4c 1168
749b1e90
MS
1169 if (!(warn & WARN_DUPLEX))
1170 errors = check_duplex(ppd, errors, verbose, 0);
1171
b94498cf 1172 if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
1173 attr->value)
1174 {
1175 /*
1176 * This file contains localizations, check for conformance of the
1177 * base translation...
1178 */
b423cd4c 1179
b94498cf 1180 if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL)
1181 {
1182 if (!attr->value || strcmp(attr->value, "ISOLatin1"))
1183 {
1184 if (!errors && !verbose)
0837b7e8 1185 _cupsLangPuts(stdout, _(" FAIL"));
b423cd4c 1186
b94498cf 1187 if (verbose >= 0)
bc44d920 1188 _cupsLangPrintf(stdout,
b94498cf 1189 _(" **FAIL** Bad LanguageEncoding %s - "
0837b7e8 1190 "must be ISOLatin1."),
b94498cf 1191 attr->value ? attr->value : "(null)");
b423cd4c 1192
b94498cf 1193 errors ++;
1194 }
b423cd4c 1195
b94498cf 1196 if (!ppd->lang_version || strcmp(ppd->lang_version, "English"))
b423cd4c 1197 {
b94498cf 1198 if (!errors && !verbose)
0837b7e8 1199 _cupsLangPuts(stdout, _(" FAIL"));
b423cd4c 1200
b94498cf 1201 if (verbose >= 0)
bc44d920 1202 _cupsLangPrintf(stdout,
b94498cf 1203 _(" **FAIL** Bad LanguageVersion %s - "
0837b7e8 1204 "must be English."),
b94498cf 1205 ppd->lang_version ? ppd->lang_version : "(null)");
b423cd4c 1206
b94498cf 1207 errors ++;
b423cd4c 1208 }
88f9aafc 1209
b94498cf 1210 /*
b423cd4c 1211 * Loop through all options and choices...
1212 */
1213
b94498cf 1214 for (option = ppdFirstOption(ppd);
b423cd4c 1215 option;
1216 option = ppdNextOption(ppd))
1217 {
b94498cf 1218 /*
1219 * Check for special characters outside A0 to BF, F7, or F8
1220 * that are used for languages other than English.
1221 */
b423cd4c 1222
b94498cf 1223 for (ptr = option->text; *ptr; ptr ++)
1224 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
1225 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
1226 break;
b423cd4c 1227
b94498cf 1228 if (*ptr)
f7deaa1a 1229 {
b94498cf 1230 if (!errors && !verbose)
0837b7e8 1231 _cupsLangPuts(stdout, _(" FAIL"));
b423cd4c 1232
b423cd4c 1233 if (verbose >= 0)
b423cd4c 1234 _cupsLangPrintf(stdout,
b94498cf 1235 _(" **FAIL** Default translation "
b423cd4c 1236 "string for option %s contains 8-bit "
0837b7e8 1237 "characters."),
b423cd4c 1238 option->keyword);
b423cd4c 1239
1240 errors ++;
1241 }
1242
b94498cf 1243 for (j = 0; j < option->num_choices; j ++)
b423cd4c 1244 {
b94498cf 1245 /*
1246 * Check for special characters outside A0 to BF, F7, or F8
1247 * that are used for languages other than English.
1248 */
d09495fa 1249
b94498cf 1250 for (ptr = option->choices[j].text; *ptr; ptr ++)
1251 if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
1252 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
1253 break;
b423cd4c 1254
b94498cf 1255 if (*ptr)
f7deaa1a 1256 {
b94498cf 1257 if (!errors && !verbose)
0837b7e8 1258 _cupsLangPuts(stdout, _(" FAIL"));
b423cd4c 1259
b423cd4c 1260 if (verbose >= 0)
b423cd4c 1261 _cupsLangPrintf(stdout,
b94498cf 1262 _(" **FAIL** Default translation "
b423cd4c 1263 "string for option %s choice %s contains "
0837b7e8 1264 "8-bit characters."),
b423cd4c 1265 option->keyword,
1266 option->choices[j].choice);
b423cd4c 1267
1268 errors ++;
1269 }
b94498cf 1270 }
b423cd4c 1271 }
b94498cf 1272 }
1273 }
c0e1af83 1274
b94498cf 1275 /*
1276 * Final pass/fail notification...
1277 */
c0e1af83 1278
b94498cf 1279 if (errors)
1280 status = ERROR_CONFORMANCE;
1281 else if (!verbose)
0837b7e8 1282 _cupsLangPuts(stdout, _(" PASS"));
c0e1af83 1283
b94498cf 1284 if (verbose >= 0)
1285 {
1286 check_basics(argv[i]);
c0e1af83 1287
b94498cf 1288 if (warn & WARN_DEFAULTS)
1289 errors = check_defaults(ppd, errors, verbose, 1);
c0e1af83 1290
b226ab99
MS
1291 if (warn & WARN_CONSTRAINTS)
1292 errors = check_constraints(ppd, errors, verbose, 1);
a603edef 1293
b226ab99 1294 if ((warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
b94498cf 1295 errors = check_filters(ppd, root, errors, verbose, 1);
c0e1af83 1296
b226ab99
MS
1297 if ((warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
1298 errors = check_profiles(ppd, root, errors, verbose, 1);
1299
1340db2d
MS
1300 if (warn & WARN_SIZES)
1301 errors = check_sizes(ppd, errors, verbose, 1);
1302 else
1303 errors = check_sizes(ppd, errors, verbose, 2);
1304
b94498cf 1305 if (warn & WARN_TRANSLATIONS)
1306 errors = check_translations(ppd, errors, verbose, 1);
c0e1af83 1307
749b1e90
MS
1308 if (warn & WARN_DUPLEX)
1309 errors = check_duplex(ppd, errors, verbose, 1);
1310
1311 /*
1312 * Look for legacy duplex keywords...
1313 */
1314
1315 if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
1316 if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
1317 option = ppdFindOption(ppd, "KD03Duplex");
1318
1319 if (option)
1320 _cupsLangPrintf(stdout,
1321 _(" WARN Duplex option keyword %s may not "
0837b7e8
MS
1322 "work as expected and should be named Duplex.\n"
1323 " REF: Page 122, section 5.17"),
749b1e90
MS
1324 option->keyword);
1325
c0e1af83 1326 /*
b94498cf 1327 * Look for default keywords with no corresponding option...
c0e1af83 1328 */
1329
b94498cf 1330 for (j = 0; j < ppd->num_attrs; j ++)
1331 {
1332 attr = ppd->attrs[j];
323c5de1 1333
b94498cf 1334 if (!strcmp(attr->name, "DefaultColorSpace") ||
1335 !strcmp(attr->name, "DefaultColorSep") ||
1336 !strcmp(attr->name, "DefaultFont") ||
09a101d6 1337 !strcmp(attr->name, "DefaultHalftoneType") ||
b94498cf 1338 !strcmp(attr->name, "DefaultImageableArea") ||
09a101d6 1339 !strcmp(attr->name, "DefaultLeadingEdge") ||
b94498cf 1340 !strcmp(attr->name, "DefaultOutputOrder") ||
1341 !strcmp(attr->name, "DefaultPaperDimension") ||
09a101d6 1342 !strcmp(attr->name, "DefaultResolution") ||
b94498cf 1343 !strcmp(attr->name, "DefaultScreenProc") ||
1344 !strcmp(attr->name, "DefaultTransfer"))
1345 continue;
b423cd4c 1346
88f9aafc 1347 if (!strncmp(attr->name, "Default", 7) &&
b94498cf 1348 !ppdFindOption(ppd, attr->name + 7))
1349 _cupsLangPrintf(stdout,
1350 _(" WARN %s has no corresponding "
0837b7e8 1351 "options."),
b94498cf 1352 attr->name);
323c5de1 1353 }
323c5de1 1354
ef416fc2 1355 if (ppdversion < 43)
1356 {
fa73b229 1357 _cupsLangPrintf(stdout,
0837b7e8
MS
1358 _(" WARN Obsolete PPD version %.1f.\n"
1359 " REF: Page 42, section 5.2."),
ef416fc2 1360 0.1f * ppdversion);
1361 }
1362
1363 if (!ppd->lang_encoding && ppdversion < 41)
1364 {
fa73b229 1365 _cupsLangPuts(stdout,
ef416fc2 1366 _(" WARN LanguageEncoding required by PPD "
1367 "4.3 spec.\n"
0837b7e8 1368 " REF: Pages 56-57, section 5.3."));
ef416fc2 1369 }
1370
1371 if (!ppd->manufacturer && ppdversion < 43)
1372 {
fa73b229 1373 _cupsLangPuts(stdout,
ef416fc2 1374 _(" WARN Manufacturer required by PPD "
1375 "4.3 spec.\n"
0837b7e8 1376 " REF: Pages 58-59, section 5.3."));
ef416fc2 1377 }
1378
1379 /*
1380 * Treat a PCFileName attribute longer than 12 characters as
1381 * a warning and not a hard error...
1382 */
1383
ef55b745
MS
1384 if (!(ignore & WARN_FILENAME) && ppd->pcfilename)
1385 {
1386 if (strlen(ppd->pcfilename) > 12)
1387 {
1388 _cupsLangPuts(stdout,
1389 _(" WARN PCFileName longer than 8.3 in "
1390 "violation of PPD spec.\n"
1391 " REF: Pages 61-62, section "
0837b7e8 1392 "5.3."));
ef55b745
MS
1393 }
1394
88f9aafc 1395 if (!_cups_strcasecmp(ppd->pcfilename, "unused.ppd"))
ef55b745
MS
1396 _cupsLangPuts(stdout,
1397 _(" WARN PCFileName should contain a "
1398 "unique filename.\n"
1399 " REF: Pages 61-62, section "
0837b7e8 1400 "5.3."));
ef416fc2 1401 }
1402
1403 if (!ppd->shortnickname && ppdversion < 43)
1404 {
fa73b229 1405 _cupsLangPuts(stdout,
ef416fc2 1406 _(" WARN ShortNickName required by PPD "
1407 "4.3 spec.\n"
0837b7e8 1408 " REF: Pages 64-65, section 5.3."));
ef416fc2 1409 }
1410
1411 /*
1412 * Check the Protocols line and flag PJL + BCP since TBCP is
1413 * usually used with PJL...
1414 */
1415
1416 if (ppd->protocols)
1417 {
1418 if (strstr(ppd->protocols, "PJL") &&
1419 strstr(ppd->protocols, "BCP") &&
1420 !strstr(ppd->protocols, "TBCP"))
1421 {
fa73b229 1422 _cupsLangPuts(stdout,
ef416fc2 1423 _(" WARN Protocols contains both PJL "
1424 "and BCP; expected TBCP.\n"
0837b7e8 1425 " REF: Pages 78-79, section 5.7."));
ef416fc2 1426 }
1427
1428 if (strstr(ppd->protocols, "PJL") &&
1429 (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps))
1430 {
fa73b229 1431 _cupsLangPuts(stdout,
ef416fc2 1432 _(" WARN Protocols contains PJL but JCL "
1433 "attributes are not set.\n"
0837b7e8 1434 " REF: Pages 78-79, section 5.7."));
ef416fc2 1435 }
1436 }
1437
1438 /*
1439 * Check for options with a common prefix, e.g. Duplex and Duplexer,
1440 * which are errors according to the spec but won't cause problems
1441 * with CUPS specifically...
1442 */
1443
1444 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
0837b7e8
MS
1445 for (k = 0, option = group->options;
1446 k < group->num_options;
1447 k ++, option ++)
ef416fc2 1448 {
7e86f2f6 1449 len = strlen(option->keyword);
ef416fc2 1450
1451 for (m = 0, group2 = ppd->groups;
1452 m < ppd->num_groups;
1453 m ++, group2 ++)
1454 for (n = 0, option2 = group2->options;
1455 n < group2->num_options;
1456 n ++, option2 ++)
1457 if (option != option2 &&
7e86f2f6 1458 len < strlen(option2->keyword) &&
ef416fc2 1459 !strncmp(option->keyword, option2->keyword, len))
1460 {
fa73b229 1461 _cupsLangPrintf(stdout,
ef416fc2 1462 _(" WARN %s shares a common "
1463 "prefix with %s\n"
1464 " REF: Page 15, section "
0837b7e8 1465 "3.2."),
ef416fc2 1466 option->keyword, option2->keyword);
1467 }
1468 }
1469 }
1470
1471 if (verbose > 0)
1472 {
1473 if (errors)
0837b7e8 1474 _cupsLangPrintf(stdout, _(" %d ERRORS FOUND"), errors);
ef416fc2 1475 else
0837b7e8 1476 _cupsLangPuts(stdout, _(" NO ERRORS FOUND"));
ef416fc2 1477 }
1478
ef416fc2 1479 /*
1480 * Then list the options, if "-v" was provided...
88f9aafc 1481 */
ef416fc2 1482
1483 if (verbose > 1)
1484 {
fa73b229 1485 _cupsLangPrintf(stdout,
ef416fc2 1486 "\n"
1487 " language_level = %d\n"
1488 " color_device = %s\n"
1489 " variable_sizes = %s\n"
0837b7e8 1490 " landscape = %d",
ef416fc2 1491 ppd->language_level,
1492 ppd->color_device ? "TRUE" : "FALSE",
1493 ppd->variable_sizes ? "TRUE" : "FALSE",
1494 ppd->landscape);
1495
1496 switch (ppd->colorspace)
1497 {
1498 case PPD_CS_CMYK :
0837b7e8 1499 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMYK");
ef416fc2 1500 break;
1501 case PPD_CS_CMY :
0837b7e8 1502 _cupsLangPuts(stdout, " colorspace = PPD_CS_CMY");
ef416fc2 1503 break;
1504 case PPD_CS_GRAY :
0837b7e8 1505 _cupsLangPuts(stdout, " colorspace = PPD_CS_GRAY");
ef416fc2 1506 break;
1507 case PPD_CS_RGB :
0837b7e8 1508 _cupsLangPuts(stdout, " colorspace = PPD_CS_RGB");
ef416fc2 1509 break;
1510 default :
0837b7e8 1511 _cupsLangPuts(stdout, " colorspace = <unknown>");
ef416fc2 1512 break;
1513 }
1514
0837b7e8 1515 _cupsLangPrintf(stdout, " num_emulations = %d",
ef416fc2 1516 ppd->num_emulations);
1517 for (j = 0; j < ppd->num_emulations; j ++)
0837b7e8 1518 _cupsLangPrintf(stdout, " emulations[%d] = %s",
ef416fc2 1519 j, ppd->emulations[j].name);
1520
0837b7e8 1521 _cupsLangPrintf(stdout, " lang_encoding = %s",
ef416fc2 1522 ppd->lang_encoding);
0837b7e8 1523 _cupsLangPrintf(stdout, " lang_version = %s",
ef416fc2 1524 ppd->lang_version);
0837b7e8
MS
1525 _cupsLangPrintf(stdout, " modelname = %s", ppd->modelname);
1526 _cupsLangPrintf(stdout, " ttrasterizer = %s",
ef416fc2 1527 ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer);
0837b7e8 1528 _cupsLangPrintf(stdout, " manufacturer = %s",
ef416fc2 1529 ppd->manufacturer);
0837b7e8
MS
1530 _cupsLangPrintf(stdout, " product = %s", ppd->product);
1531 _cupsLangPrintf(stdout, " nickname = %s", ppd->nickname);
1532 _cupsLangPrintf(stdout, " shortnickname = %s",
ef416fc2 1533 ppd->shortnickname);
0837b7e8 1534 _cupsLangPrintf(stdout, " patches = %d bytes",
ef416fc2 1535 ppd->patches == NULL ? 0 : (int)strlen(ppd->patches));
1536
0837b7e8 1537 _cupsLangPrintf(stdout, " num_groups = %d", ppd->num_groups);
ef416fc2 1538 for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
1539 {
0837b7e8 1540 _cupsLangPrintf(stdout, " group[%d] = %s",
ef416fc2 1541 j, group->text);
1542
1543 for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
1544 {
fa73b229 1545 _cupsLangPrintf(stdout,
ef416fc2 1546 " options[%d] = %s (%s) %s %s %.0f "
0837b7e8 1547 "(%d choices)",
ef416fc2 1548 k, option->keyword, option->text, uis[option->ui],
1549 sections[option->section], option->order,
1550 option->num_choices);
1551
1552 if (!strcmp(option->keyword, "PageSize") ||
1553 !strcmp(option->keyword, "PageRegion"))
1554 {
1555 for (m = option->num_choices, choice = option->choices;
1556 m > 0;
1557 m --, choice ++)
1558 {
1559 size = ppdPageSize(ppd, choice->choice);
1560
1561 if (size == NULL)
fa73b229 1562 _cupsLangPrintf(stdout,
0837b7e8
MS
1563 " %s (%s) = ERROR%s",
1564 choice->choice, choice->text,
1565 !strcmp(option->defchoice, choice->choice)
1566 ? " *" : "");
ef416fc2 1567 else
fa73b229 1568 _cupsLangPrintf(stdout,
ef416fc2 1569 " %s (%s) = %.2fx%.2fin "
0837b7e8 1570 "(%.1f,%.1f,%.1f,%.1f)%s",
ef416fc2 1571 choice->choice, choice->text,
1572 size->width / 72.0, size->length / 72.0,
1573 size->left / 72.0, size->bottom / 72.0,
0837b7e8
MS
1574 size->right / 72.0, size->top / 72.0,
1575 !strcmp(option->defchoice, choice->choice)
1576 ? " *" : "");
ef416fc2 1577 }
1578 }
1579 else
1580 {
1581 for (m = option->num_choices, choice = option->choices;
1582 m > 0;
1583 m --, choice ++)
1584 {
0837b7e8
MS
1585 _cupsLangPrintf(stdout, " %s (%s)%s",
1586 choice->choice, choice->text,
1587 !strcmp(option->defchoice, choice->choice)
1588 ? " *" : "");
ef416fc2 1589 }
1590 }
1591 }
1592 }
1593
0837b7e8 1594 _cupsLangPrintf(stdout, " num_consts = %d",
09a101d6 1595 ppd->num_consts);
1596 for (j = 0; j < ppd->num_consts; j ++)
1597 _cupsLangPrintf(stdout,
0837b7e8 1598 " consts[%d] = *%s %s *%s %s",
09a101d6 1599 j, ppd->consts[j].option1, ppd->consts[j].choice1,
1600 ppd->consts[j].option2, ppd->consts[j].choice2);
1601
0837b7e8 1602 _cupsLangPrintf(stdout, " num_profiles = %d",
ef416fc2 1603 ppd->num_profiles);
1604 for (j = 0; j < ppd->num_profiles; j ++)
fa73b229 1605 _cupsLangPrintf(stdout,
ef416fc2 1606 " profiles[%d] = %s/%s %.3f %.3f "
0837b7e8 1607 "[ %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ]",
ef416fc2 1608 j, ppd->profiles[j].resolution,
1609 ppd->profiles[j].media_type,
1610 ppd->profiles[j].gamma, ppd->profiles[j].density,
1611 ppd->profiles[j].matrix[0][0],
1612 ppd->profiles[j].matrix[0][1],
1613 ppd->profiles[j].matrix[0][2],
1614 ppd->profiles[j].matrix[1][0],
1615 ppd->profiles[j].matrix[1][1],
1616 ppd->profiles[j].matrix[1][2],
1617 ppd->profiles[j].matrix[2][0],
1618 ppd->profiles[j].matrix[2][1],
1619 ppd->profiles[j].matrix[2][2]);
1620
0837b7e8 1621 _cupsLangPrintf(stdout, " num_fonts = %d", ppd->num_fonts);
ef416fc2 1622 for (j = 0; j < ppd->num_fonts; j ++)
0837b7e8 1623 _cupsLangPrintf(stdout, " fonts[%d] = %s",
ef416fc2 1624 j, ppd->fonts[j]);
1625
0837b7e8 1626 _cupsLangPrintf(stdout, " num_attrs = %d", ppd->num_attrs);
ef416fc2 1627 for (j = 0; j < ppd->num_attrs; j ++)
fa73b229 1628 _cupsLangPrintf(stdout,
0837b7e8 1629 " attrs[%d] = %s %s%s%s: \"%s\"", j,
ef416fc2 1630 ppd->attrs[j]->name, ppd->attrs[j]->spec,
1631 ppd->attrs[j]->text[0] ? "/" : "",
1632 ppd->attrs[j]->text,
1633 ppd->attrs[j]->value ?
1634 ppd->attrs[j]->value : "(null)");
1635 }
1636
1637 ppdClose(ppd);
1638 }
1639
1640 if (!files)
1641 usage();
1642
1643 return (status);
1644}
1645
1646
fa73b229 1647/*
1648 * 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
1649 */
1650
3d8365b8 1651static void
fa73b229 1652check_basics(const char *filename) /* I - PPD file to check */
1653{
1654 cups_file_t *fp; /* File pointer */
1655 int ch; /* Current character */
1656 int col, /* Current column */
1657 whitespace; /* Only seen whitespace? */
1658 int eol; /* Line endings */
1659 int linenum; /* Line number */
1660 int mixed; /* Mixed line endings? */
1661
1662
1663 if ((fp = cupsFileOpen(filename, "r")) == NULL)
1664 return;
1665
1666 linenum = 1;
1667 col = 0;
1668 eol = EOL_NONE;
1669 mixed = 0;
1670 whitespace = 1;
1671
1672 while ((ch = cupsFileGetChar(fp)) != EOF)
1673 {
1674 if (ch == '\r' || ch == '\n')
1675 {
1676 if (ch == '\n')
1677 {
1678 if (eol == EOL_NONE)
1679 eol = EOL_LF;
1680 else if (eol != EOL_LF)
1681 mixed = 1;
1682 }
1683 else if (ch == '\r')
1684 {
1685 if (cupsFilePeekChar(fp) == '\n')
1686 {
1687 cupsFileGetChar(fp);
1688
1689 if (eol == EOL_NONE)
1690 eol = EOL_CRLF;
1f0275e3 1691 else if (eol != EOL_CRLF)
fa73b229 1692 mixed = 1;
1693 }
1694 else if (eol == EOL_NONE)
1695 eol = EOL_CR;
1f0275e3 1696 else if (eol != EOL_CR)
fa73b229 1697 mixed = 1;
1698 }
88f9aafc 1699
fa73b229 1700 if (col > 0 && whitespace)
1701 _cupsLangPrintf(stdout,
0837b7e8 1702 _(" WARN Line %d only contains whitespace."),
fa73b229 1703 linenum);
1704
1705 linenum ++;
1706 col = 0;
1707 whitespace = 1;
1708 }
1709 else
1710 {
1711 if (ch != ' ' && ch != '\t')
1712 whitespace = 0;
1713
1714 col ++;
1715 }
1716 }
1717
1718 if (mixed)
1719 _cupsLangPuts(stdout,
1720 _(" WARN File contains a mix of CR, LF, and "
0837b7e8 1721 "CR LF line endings."));
fa73b229 1722
1723 if (eol == EOL_CRLF)
1724 _cupsLangPuts(stdout,
1725 _(" WARN Non-Windows PPD files should use lines "
0837b7e8 1726 "ending with only LF, not CR LF."));
fa73b229 1727
1728 cupsFileClose(fp);
1729}
1730
1731
b94498cf 1732/*
1733 * 'check_constraints()' - Check UIConstraints in the PPD file.
1734 */
1735
3d8365b8 1736static int /* O - Errors found */
b94498cf 1737check_constraints(ppd_file_t *ppd, /* I - PPD file */
1738 int errors, /* I - Errors found */
1739 int verbose, /* I - Verbosity level */
1740 int warn) /* I - Warnings only? */
1741{
66ab9486
MS
1742 int i; /* Looping var */
1743 const char *prefix; /* WARN/FAIL prefix */
1744 ppd_const_t *c; /* Current UIConstraints data */
1745 ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
1746 const char *vptr; /* Pointer into constraint value */
1747 char option[PPD_MAX_NAME],
1748 /* Option name/MainKeyword */
1749 choice[PPD_MAX_NAME],
1750 /* Choice/OptionKeyword */
1751 *ptr; /* Pointer into option or choice */
1752 int num_options; /* Number of options */
1753 cups_option_t *options; /* Options */
1754 ppd_option_t *o; /* PPD option */
b94498cf 1755
1756
1757 prefix = warn ? " WARN " : "**FAIL**";
1758
66ab9486
MS
1759
1760 /*
1761 * See what kind of constraint data we have in the PPD...
1762 */
1763
1764 if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL)
1765 {
1766 /*
1767 * Check new-style cupsUIConstraints data...
1768 */
1769
1770 for (; constattr;
1771 constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
1772 {
1773 if (!constattr->value)
1774 {
1775 if (!warn && !errors && !verbose)
0837b7e8 1776 _cupsLangPuts(stdout, _(" FAIL"));
66ab9486
MS
1777
1778 _cupsLangPrintf(stdout,
0837b7e8 1779 _(" %s Empty cupsUIConstraints %s"),
66ab9486
MS
1780 prefix, constattr->spec);
1781
1782 if (!warn)
1783 errors ++;
1784
1785 continue;
1786 }
1787
1788 for (i = 0, vptr = strchr(constattr->value, '*');
1789 vptr;
1790 i ++, vptr = strchr(vptr + 1, '*'));
1791
1792 if (i == 0)
1793 {
1794 if (!warn && !errors && !verbose)
0837b7e8 1795 _cupsLangPuts(stdout, _(" FAIL"));
66ab9486
MS
1796
1797 _cupsLangPrintf(stdout,
0837b7e8 1798 _(" %s Bad cupsUIConstraints %s: \"%s\""),
66ab9486
MS
1799 prefix, constattr->spec, constattr->value);
1800
1801 if (!warn)
1802 errors ++;
1803
1804 continue;
1805 }
1806
1807 cupsArraySave(ppd->sorted_attrs);
1808
1809 if (constattr->spec[0] &&
1810 !ppdFindAttr(ppd, "cupsUIResolver", constattr->spec))
1811 {
1812 if (!warn && !errors && !verbose)
0837b7e8 1813 _cupsLangPuts(stdout, _(" FAIL"));
66ab9486
MS
1814
1815 _cupsLangPrintf(stdout,
0837b7e8 1816 _(" %s Missing cupsUIResolver %s"),
66ab9486
MS
1817 prefix, constattr->spec);
1818
1819 if (!warn)
1820 errors ++;
1821 }
1822
1823 cupsArrayRestore(ppd->sorted_attrs);
1824
1825 num_options = 0;
1826 options = NULL;
1827
1828 for (vptr = strchr(constattr->value, '*');
1829 vptr;
005dd1eb 1830 vptr = strchr(vptr, '*'))
66ab9486
MS
1831 {
1832 /*
1833 * Extract "*Option Choice" or just "*Option"...
1834 */
1835
1836 for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
1837 if (ptr < (option + sizeof(option) - 1))
1838 *ptr++ = *vptr;
1839
1840 *ptr = '\0';
1841
1842 while (isspace(*vptr & 255))
1843 vptr ++;
1844
1845 if (*vptr == '*')
66ab9486 1846 choice[0] = '\0';
66ab9486
MS
1847 else
1848 {
1849 for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
1850 if (ptr < (choice + sizeof(choice) - 1))
1851 *ptr++ = *vptr;
1852
1853 *ptr = '\0';
1854 }
1855
88f9aafc 1856 if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True"))
66ab9486
MS
1857 {
1858 _cups_strcpy(option, option + 6);
5a9febac 1859 strlcpy(choice, "Custom", sizeof(choice));
66ab9486
MS
1860 }
1861
1862 if ((o = ppdFindOption(ppd, option)) == NULL)
1863 {
1864 if (!warn && !errors && !verbose)
0837b7e8 1865 _cupsLangPuts(stdout, _(" FAIL"));
66ab9486
MS
1866
1867 _cupsLangPrintf(stdout,
1868 _(" %s Missing option %s in "
0837b7e8 1869 "cupsUIConstraints %s: \"%s\""),
66ab9486 1870 prefix, option, constattr->spec, constattr->value);
88f9aafc 1871
66ab9486
MS
1872 if (!warn)
1873 errors ++;
1874
1875 continue;
1876 }
1877
1878 if (choice[0] && !ppdFindChoice(o, choice))
1879 {
1880 if (!warn && !errors && !verbose)
0837b7e8 1881 _cupsLangPuts(stdout, _(" FAIL"));
66ab9486
MS
1882
1883 _cupsLangPrintf(stdout,
1884 _(" %s Missing choice *%s %s in "
0837b7e8 1885 "cupsUIConstraints %s: \"%s\""),
66ab9486
MS
1886 prefix, option, choice, constattr->spec,
1887 constattr->value);
1888
1889 if (!warn)
1890 errors ++;
1891
1892 continue;
1893 }
1894
1895 if (choice[0])
1896 num_options = cupsAddOption(option, choice, num_options, &options);
1897 else
1898 {
1899 for (i = 0; i < o->num_choices; i ++)
88f9aafc
MS
1900 if (_cups_strcasecmp(o->choices[i].choice, "None") &&
1901 _cups_strcasecmp(o->choices[i].choice, "Off") &&
1902 _cups_strcasecmp(o->choices[i].choice, "False"))
66ab9486
MS
1903 {
1904 num_options = cupsAddOption(option, o->choices[i].choice,
1905 num_options, &options);
1906 break;
1907 }
1908 }
1909 }
1910
1340db2d
MS
1911 /*
1912 * Resolvers must list at least two options...
1913 */
1914
1915 if (num_options < 2)
1916 {
1917 if (!warn && !errors && !verbose)
0837b7e8 1918 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
1919
1920 _cupsLangPrintf(stdout,
1921 _(" %s cupsUIResolver %s does not list at least "
0837b7e8 1922 "two different options."),
1340db2d
MS
1923 prefix, constattr->spec);
1924
1925 if (!warn)
1926 errors ++;
1927 }
1928
66ab9486
MS
1929 /*
1930 * Test the resolver...
1931 */
1932
1933 if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
1934 {
1935 if (!warn && !errors && !verbose)
0837b7e8 1936 _cupsLangPuts(stdout, _(" FAIL"));
66ab9486
MS
1937
1938 _cupsLangPrintf(stdout,
0837b7e8 1939 _(" %s cupsUIResolver %s causes a loop."),
66ab9486
MS
1940 prefix, constattr->spec);
1941
1942 if (!warn)
1943 errors ++;
1944 }
1945
1946 cupsFreeOptions(num_options, options);
1947 }
1948 }
1949 else
b94498cf 1950 {
66ab9486
MS
1951 /*
1952 * Check old-style [Non]UIConstraints data...
1953 */
b94498cf 1954
66ab9486 1955 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
b94498cf 1956 {
88f9aafc
MS
1957 if (!_cups_strncasecmp(c->option1, "Custom", 6) &&
1958 !_cups_strcasecmp(c->choice1, "True"))
66ab9486 1959 {
5a9febac
MS
1960 strlcpy(option, c->option1 + 6, sizeof(option));
1961 strlcpy(choice, "Custom", sizeof(choice));
66ab9486
MS
1962 }
1963 else
1964 {
5a9febac
MS
1965 strlcpy(option, c->option1, sizeof(option));
1966 strlcpy(choice, c->choice1, sizeof(choice));
66ab9486
MS
1967 }
1968
1969 if ((o = ppdFindOption(ppd, option)) == NULL)
1970 {
1971 if (!warn && !errors && !verbose)
0837b7e8 1972 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 1973
b94498cf 1974 _cupsLangPrintf(stdout,
1975 _(" %s Missing option %s in "
0837b7e8 1976 "UIConstraints \"*%s %s *%s %s\"."),
b94498cf 1977 prefix, c->option1,
1978 c->option1, c->choice1, c->option2, c->choice2);
66ab9486
MS
1979
1980 if (!warn)
1981 errors ++;
1982 }
1983 else if (choice[0] && !ppdFindChoice(o, choice))
1984 {
1985 if (!warn && !errors && !verbose)
0837b7e8 1986 _cupsLangPuts(stdout, _(" FAIL"));
66ab9486 1987
b94498cf 1988 _cupsLangPrintf(stdout,
66ab9486 1989 _(" %s Missing choice *%s %s in "
0837b7e8 1990 "UIConstraints \"*%s %s *%s %s\"."),
66ab9486 1991 prefix, c->option1, c->choice1,
b94498cf 1992 c->option1, c->choice1, c->option2, c->choice2);
1993
66ab9486
MS
1994 if (!warn)
1995 errors ++;
1996 }
b94498cf 1997
88f9aafc
MS
1998 if (!_cups_strncasecmp(c->option2, "Custom", 6) &&
1999 !_cups_strcasecmp(c->choice2, "True"))
66ab9486 2000 {
5a9febac
MS
2001 strlcpy(option, c->option2 + 6, sizeof(option));
2002 strlcpy(choice, "Custom", sizeof(choice));
66ab9486
MS
2003 }
2004 else
2005 {
5a9febac
MS
2006 strlcpy(option, c->option2, sizeof(option));
2007 strlcpy(choice, c->choice2, sizeof(choice));
66ab9486 2008 }
b94498cf 2009
66ab9486
MS
2010 if ((o = ppdFindOption(ppd, option)) == NULL)
2011 {
2012 if (!warn && !errors && !verbose)
0837b7e8 2013 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 2014
66ab9486
MS
2015 _cupsLangPrintf(stdout,
2016 _(" %s Missing option %s in "
0837b7e8 2017 "UIConstraints \"*%s %s *%s %s\"."),
66ab9486
MS
2018 prefix, c->option2,
2019 c->option1, c->choice1, c->option2, c->choice2);
b94498cf 2020
66ab9486
MS
2021 if (!warn)
2022 errors ++;
2023 }
2024 else if (choice[0] && !ppdFindChoice(o, choice))
2025 {
2026 if (!warn && !errors && !verbose)
0837b7e8 2027 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 2028
66ab9486
MS
2029 _cupsLangPrintf(stdout,
2030 _(" %s Missing choice *%s %s in "
0837b7e8 2031 "UIConstraints \"*%s %s *%s %s\"."),
66ab9486
MS
2032 prefix, c->option2, c->choice2,
2033 c->option1, c->choice1, c->option2, c->choice2);
b94498cf 2034
66ab9486
MS
2035 if (!warn)
2036 errors ++;
2037 }
b94498cf 2038 }
2039 }
2040
2041 return (errors);
2042}
2043
2044
749b1e90
MS
2045/*
2046 * 'check_case()' - Check that there are no duplicate groups, options,
2047 * or choices that differ only by case.
2048 */
2049
2050static int /* O - Errors found */
2051check_case(ppd_file_t *ppd, /* I - PPD file */
2052 int errors, /* I - Errors found */
2053 int verbose) /* I - Verbosity level */
2054{
2055 int i, j; /* Looping vars */
2056 ppd_group_t *groupa, /* First group */
2057 *groupb; /* Second group */
2058 ppd_option_t *optiona, /* First option */
2059 *optionb; /* Second option */
2060 ppd_choice_t *choicea, /* First choice */
2061 *choiceb; /* Second choice */
2062
2063
2064 /*
2065 * Check that the groups do not have any duplicate names...
2066 */
2067
2068 for (i = ppd->num_groups, groupa = ppd->groups; i > 1; i --, groupa ++)
2069 for (j = i - 1, groupb = groupa + 1; j > 0; j --, groupb ++)
88f9aafc 2070 if (!_cups_strcasecmp(groupa->name, groupb->name))
749b1e90
MS
2071 {
2072 if (!errors && !verbose)
0837b7e8 2073 _cupsLangPuts(stdout, _(" FAIL"));
749b1e90
MS
2074
2075 if (verbose >= 0)
2076 _cupsLangPrintf(stdout,
2077 _(" **FAIL** Group names %s and %s differ only "
0837b7e8 2078 "by case."),
749b1e90
MS
2079 groupa->name, groupb->name);
2080
2081 errors ++;
2082 }
2083
2084 /*
2085 * Check that the options do not have any duplicate names...
2086 */
2087
2088 for (optiona = ppdFirstOption(ppd); optiona; optiona = ppdNextOption(ppd))
2089 {
2090 cupsArraySave(ppd->options);
2091 for (optionb = ppdNextOption(ppd); optionb; optionb = ppdNextOption(ppd))
88f9aafc 2092 if (!_cups_strcasecmp(optiona->keyword, optionb->keyword))
749b1e90
MS
2093 {
2094 if (!errors && !verbose)
0837b7e8 2095 _cupsLangPuts(stdout, _(" FAIL"));
749b1e90
MS
2096
2097 if (verbose >= 0)
2098 _cupsLangPrintf(stdout,
2099 _(" **FAIL** Option names %s and %s differ only "
0837b7e8 2100 "by case."),
749b1e90
MS
2101 optiona->keyword, optionb->keyword);
2102
2103 errors ++;
2104 }
2105 cupsArrayRestore(ppd->options);
2106
2107 /*
2108 * Then the choices...
2109 */
2110
2111 for (i = optiona->num_choices, choicea = optiona->choices;
2112 i > 1;
2113 i --, choicea ++)
2114 for (j = i - 1, choiceb = choicea + 1; j > 0; j --, choiceb ++)
2115 if (!strcmp(choicea->choice, choiceb->choice))
2116 {
2117 if (!errors && !verbose)
0837b7e8 2118 _cupsLangPuts(stdout, _(" FAIL"));
749b1e90
MS
2119
2120 if (verbose >= 0)
2121 _cupsLangPrintf(stdout,
f3c17241
MS
2122 _(" **FAIL** Multiple occurrences of "
2123 "option %s choice name %s."),
749b1e90
MS
2124 optiona->keyword, choicea->choice);
2125
2126 errors ++;
2127
2128 choicea ++;
2129 i --;
2130 break;
2131 }
88f9aafc 2132 else if (!_cups_strcasecmp(choicea->choice, choiceb->choice))
749b1e90
MS
2133 {
2134 if (!errors && !verbose)
0837b7e8 2135 _cupsLangPuts(stdout, _(" FAIL"));
749b1e90
MS
2136
2137 if (verbose >= 0)
2138 _cupsLangPrintf(stdout,
f3c17241
MS
2139 _(" **FAIL** Option %s choice names %s and "
2140 "%s differ only by case."),
749b1e90
MS
2141 optiona->keyword, choicea->choice, choiceb->choice);
2142
2143 errors ++;
2144 }
2145 }
2146
2147 /*
2148 * Return the number of errors found...
2149 */
2150
2151 return (errors);
2152}
2153
2154
b94498cf 2155/*
2156 * 'check_defaults()' - Check default option keywords in the PPD file.
2157 */
2158
3d8365b8 2159static int /* O - Errors found */
b94498cf 2160check_defaults(ppd_file_t *ppd, /* I - PPD file */
2161 int errors, /* I - Errors found */
2162 int verbose, /* I - Verbosity level */
2163 int warn) /* I - Warnings only? */
2164{
2165 int j, k; /* Looping vars */
2166 ppd_attr_t *attr; /* PPD attribute */
2167 ppd_option_t *option; /* Standard UI option */
2168 const char *prefix; /* WARN/FAIL prefix */
2169
2170
2171 prefix = warn ? " WARN " : "**FAIL**";
2172
22c9029b
MS
2173 ppdMarkDefaults(ppd);
2174 if (ppdConflicts(ppd))
2175 {
2176 if (!warn && !errors && !verbose)
2177 _cupsLangPuts(stdout, _(" FAIL"));
2178
2179 if (verbose >= 0)
2180 _cupsLangPrintf(stdout,
2181 _(" %s Default choices conflicting."), prefix);
2182
2183 show_conflicts(ppd, prefix);
2184
2185 if (!warn)
2186 errors ++;
2187 }
2188
b94498cf 2189 for (j = 0; j < ppd->num_attrs; j ++)
2190 {
2191 attr = ppd->attrs[j];
2192
2193 if (!strcmp(attr->name, "DefaultColorSpace") ||
2194 !strcmp(attr->name, "DefaultFont") ||
09a101d6 2195 !strcmp(attr->name, "DefaultHalftoneType") ||
b94498cf 2196 !strcmp(attr->name, "DefaultImageableArea") ||
09a101d6 2197 !strcmp(attr->name, "DefaultLeadingEdge") ||
b94498cf 2198 !strcmp(attr->name, "DefaultOutputOrder") ||
2199 !strcmp(attr->name, "DefaultPaperDimension") ||
2200 !strcmp(attr->name, "DefaultResolution") ||
2201 !strcmp(attr->name, "DefaultTransfer"))
2202 continue;
2203
2204 if (!strncmp(attr->name, "Default", 7))
2205 {
2206 if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
2207 strcmp(attr->value, "Unknown"))
2208 {
2209 /*
2210 * Check that the default option value matches a choice...
2211 */
2212
2213 for (k = 0; k < option->num_choices; k ++)
2214 if (!strcmp(option->choices[k].choice, attr->value))
2215 break;
2216
2217 if (k >= option->num_choices)
2218 {
2219 if (!warn && !errors && !verbose)
0837b7e8 2220 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 2221
2222 if (verbose >= 0)
2223 _cupsLangPrintf(stdout,
0837b7e8 2224 _(" %s %s %s does not exist."),
b94498cf 2225 prefix, attr->name, attr->value);
2226
2227 if (!warn)
2228 errors ++;
2229 }
2230 }
2231 }
2232 }
2233
2234 return (errors);
2235}
2236
2237
749b1e90
MS
2238/*
2239 * 'check_duplex()' - Check duplex keywords in the PPD file.
2240 */
2241
2242static int /* O - Errors found */
2243check_duplex(ppd_file_t *ppd, /* I - PPD file */
2244 int errors, /* I - Error found */
2245 int verbose, /* I - Verbosity level */
2246 int warn) /* I - Warnings only? */
2247{
2248 int i; /* Looping var */
2249 ppd_option_t *option; /* PPD option */
2250 ppd_choice_t *choice; /* Current choice */
2251 const char *prefix; /* Message prefix */
2252
2253
2254 prefix = warn ? " WARN " : "**FAIL**";
2255
2256 /*
2257 * Check for a duplex option, and for standard values...
2258 */
2259
2260 if ((option = ppdFindOption(ppd, "Duplex")) != NULL)
2261 {
2262 if (!ppdFindChoice(option, "None"))
2263 {
2264 if (verbose >= 0)
2265 {
2266 if (!warn && !errors && !verbose)
0837b7e8 2267 _cupsLangPuts(stdout, _(" FAIL"));
749b1e90
MS
2268
2269 _cupsLangPrintf(stdout,
2270 _(" %s REQUIRED %s does not define "
0837b7e8
MS
2271 "choice None.\n"
2272 " REF: Page 122, section 5.17"),
749b1e90
MS
2273 prefix, option->keyword);
2274 }
2275
2276 if (!warn)
2277 errors ++;
2278 }
2279
2280 for (i = option->num_choices, choice = option->choices;
2281 i > 0;
2282 i --, choice ++)
2283 if (strcmp(choice->choice, "None") &&
2284 strcmp(choice->choice, "DuplexNoTumble") &&
2285 strcmp(choice->choice, "DuplexTumble") &&
2286 strcmp(choice->choice, "SimplexTumble"))
2287 {
2288 if (verbose >= 0)
2289 {
2290 if (!warn && !errors && !verbose)
0837b7e8 2291 _cupsLangPuts(stdout, _(" FAIL"));
749b1e90
MS
2292
2293 _cupsLangPrintf(stdout,
0837b7e8
MS
2294 _(" %s Bad %s choice %s.\n"
2295 " REF: Page 122, section 5.17"),
749b1e90
MS
2296 prefix, option->keyword, choice->choice);
2297 }
2298
2299 if (!warn)
2300 errors ++;
2301 }
2302 }
2303
2304 return (errors);
2305}
2306
2307
b94498cf 2308/*
2309 * 'check_filters()' - Check filters in the PPD file.
2310 */
2311
3d8365b8 2312static int /* O - Errors found */
b94498cf 2313check_filters(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 ppd_attr_t *attr; /* PPD attribute */
2320 const char *ptr; /* Pointer into string */
b94498cf 2321 char super[16], /* Super-type for filter */
2322 type[256], /* Type for filter */
a4845881
MS
2323 dstsuper[16], /* Destination super-type for filter */
2324 dsttype[256], /* Destination type for filter */
1f0275e3 2325 program[1024], /* Program/filter name */
b94498cf 2326 pathprog[1024]; /* Complete path to program/filter */
2327 int cost; /* Cost of filter */
2328 const char *prefix; /* WARN/FAIL prefix */
b226ab99 2329 struct stat fileinfo; /* File information */
b94498cf 2330
2331
2332 prefix = warn ? " WARN " : "**FAIL**";
2333
1340db2d
MS
2334 /*
2335 * cupsFilter
2336 */
2337
a4845881
MS
2338 for (attr = ppdFindAttr(ppd, "cupsFilter", NULL);
2339 attr;
2340 attr = ppdFindNextAttr(ppd, "cupsFilter", NULL))
b94498cf 2341 {
a4845881
MS
2342 if (strcmp(attr->name, "cupsFilter"))
2343 {
2344 if (!warn && !errors && !verbose)
2345 _cupsLangPuts(stdout, _(" FAIL"));
2346
2347 if (verbose >= 0)
2348 _cupsLangPrintf(stdout,
2349 _(" %s Bad spelling of %s - should be %s."),
2350 prefix, attr->name, "cupsFilter");
2351
2352 if (!warn)
2353 errors ++;
2354 }
2355
2356 if (!attr->value ||
2357 sscanf(attr->value, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
1f0275e3 2358 &cost, program) != 4)
b94498cf 2359 {
2360 if (!warn && !errors && !verbose)
0837b7e8 2361 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 2362
2363 if (verbose >= 0)
2364 _cupsLangPrintf(stdout,
0837b7e8 2365 _(" %s Bad cupsFilter value \"%s\"."),
85dda01c 2366 prefix, attr->value);
b94498cf 2367
2368 if (!warn)
2369 errors ++;
ea72cf2b
MS
2370
2371 continue;
2372 }
2373
2374 if (!strncmp(program, "maxsize(", 8))
2375 {
f8f7636e 2376 char *mptr; /* Pointer into maxsize(nnnn) program */
ea72cf2b 2377
c8fdb001 2378 strtoll(program + 8, &mptr, 10);
ea72cf2b 2379
f8f7636e 2380 if (*mptr != ')')
ea72cf2b
MS
2381 {
2382 if (!warn && !errors && !verbose)
2383 _cupsLangPuts(stdout, _(" FAIL"));
2384
2385 if (verbose >= 0)
2386 _cupsLangPrintf(stdout,
2387 _(" %s Bad cupsFilter value \"%s\"."),
2388 prefix, attr->value);
2389
2390 if (!warn)
2391 errors ++;
2392
2393 continue;
2394 }
2395
f8f7636e
MS
2396 mptr ++;
2397 while (_cups_isspace(*mptr))
2398 mptr ++;
ea72cf2b 2399
f8f7636e 2400 _cups_strcpy(program, mptr);
b94498cf 2401 }
ea72cf2b
MS
2402
2403 if (strcmp(program, "-"))
b94498cf 2404 {
2405 if (program[0] == '/')
2406 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
2407 else
2408 {
2409 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
2410 ptr = CUPS_SERVERBIN;
2411
2412 if (*ptr == '/' || !*root)
2413 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
2414 program);
2415 else
2416 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
2417 program);
2418 }
2419
b226ab99 2420 if (stat(pathprog, &fileinfo))
b94498cf 2421 {
2422 if (!warn && !errors && !verbose)
0837b7e8 2423 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 2424
2425 if (verbose >= 0)
84315f46
MS
2426 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2427 prefix, "cupsFilter", pathprog);
b226ab99
MS
2428
2429 if (!warn)
2430 errors ++;
2431 }
2432 else if (fileinfo.st_uid != 0 ||
2433 (fileinfo.st_mode & MODE_WRITE) ||
2434 (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
2435 {
2436 if (!warn && !errors && !verbose)
0837b7e8 2437 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
2438
2439 if (verbose >= 0)
84315f46
MS
2440 _cupsLangPrintf(stdout,
2441 _(" %s Bad permissions on %s file \"%s\"."),
2442 prefix, "cupsFilter", pathprog);
b94498cf 2443
2444 if (!warn)
2445 errors ++;
2446 }
1340db2d
MS
2447 else
2448 errors = valid_path("cupsFilter", pathprog, errors, verbose, warn);
b94498cf 2449 }
2450 }
2451
a4845881
MS
2452 /*
2453 * cupsFilter2
2454 */
2455
2456 for (attr = ppdFindAttr(ppd, "cupsFilter2", NULL);
2457 attr;
2458 attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL))
2459 {
2460 if (strcmp(attr->name, "cupsFilter2"))
2461 {
2462 if (!warn && !errors && !verbose)
2463 _cupsLangPuts(stdout, _(" FAIL"));
2464
2465 if (verbose >= 0)
2466 _cupsLangPrintf(stdout,
2467 _(" %s Bad spelling of %s - should be %s."),
2468 prefix, attr->name, "cupsFilter2");
2469
2470 if (!warn)
2471 errors ++;
2472 }
2473
2474 if (!attr->value ||
2475 sscanf(attr->value, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
2476 super, type, dstsuper, dsttype, &cost, program) != 6)
2477 {
2478 if (!warn && !errors && !verbose)
2479 _cupsLangPuts(stdout, _(" FAIL"));
2480
2481 if (verbose >= 0)
2482 _cupsLangPrintf(stdout,
2483 _(" %s Bad cupsFilter2 value \"%s\"."),
85dda01c 2484 prefix, attr->value);
a4845881
MS
2485
2486 if (!warn)
2487 errors ++;
ea72cf2b
MS
2488
2489 continue;
2490 }
2491
2492 if (!strncmp(program, "maxsize(", 8))
2493 {
f8f7636e 2494 char *mptr; /* Pointer into maxsize(nnnn) program */
ea72cf2b 2495
c8fdb001 2496 strtoll(program + 8, &mptr, 10);
ea72cf2b 2497
f8f7636e 2498 if (*mptr != ')')
ea72cf2b
MS
2499 {
2500 if (!warn && !errors && !verbose)
2501 _cupsLangPuts(stdout, _(" FAIL"));
2502
2503 if (verbose >= 0)
2504 _cupsLangPrintf(stdout,
2505 _(" %s Bad cupsFilter2 value \"%s\"."),
2506 prefix, attr->value);
2507
2508 if (!warn)
2509 errors ++;
2510
2511 continue;
2512 }
2513
f8f7636e
MS
2514 mptr ++;
2515 while (_cups_isspace(*mptr))
2516 mptr ++;
ea72cf2b 2517
f8f7636e 2518 _cups_strcpy(program, mptr);
a4845881 2519 }
ea72cf2b
MS
2520
2521 if (strcmp(program, "-"))
a4845881
MS
2522 {
2523 if (strncmp(program, "maxsize(", 8) &&
2524 (ptr = strchr(program + 8, ')')) != NULL)
2525 {
2526 ptr ++;
2527 while (_cups_isspace(*ptr))
2528 ptr ++;
2529
2530 _cups_strcpy(program, ptr);
2531 }
2532
2533 if (program[0] == '/')
2534 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
2535 else
2536 {
2537 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
2538 ptr = CUPS_SERVERBIN;
2539
2540 if (*ptr == '/' || !*root)
2541 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
2542 program);
2543 else
2544 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
2545 program);
2546 }
2547
2548 if (stat(pathprog, &fileinfo))
2549 {
2550 if (!warn && !errors && !verbose)
2551 _cupsLangPuts(stdout, _(" FAIL"));
2552
2553 if (verbose >= 0)
2554 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2555 prefix, "cupsFilter2", pathprog);
2556
2557 if (!warn)
2558 errors ++;
2559 }
2560 else if (fileinfo.st_uid != 0 ||
2561 (fileinfo.st_mode & MODE_WRITE) ||
2562 (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
2563 {
2564 if (!warn && !errors && !verbose)
2565 _cupsLangPuts(stdout, _(" FAIL"));
2566
2567 if (verbose >= 0)
2568 _cupsLangPrintf(stdout,
2569 _(" %s Bad permissions on %s file \"%s\"."),
2570 prefix, "cupsFilter2", pathprog);
2571
2572 if (!warn)
2573 errors ++;
2574 }
2575 else
2576 errors = valid_path("cupsFilter2", pathprog, errors, verbose, warn);
2577 }
2578 }
2579
1340db2d
MS
2580 /*
2581 * cupsPreFilter
2582 */
2583
b94498cf 2584 for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
2585 attr;
2586 attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
2587 {
8b116e60
MS
2588 if (strcmp(attr->name, "cupsPreFilter"))
2589 {
2590 if (!warn && !errors && !verbose)
0837b7e8 2591 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2592
2593 if (verbose >= 0)
2594 _cupsLangPrintf(stdout,
0837b7e8 2595 _(" %s Bad spelling of %s - should be %s."),
8b116e60
MS
2596 prefix, attr->name, "cupsPreFilter");
2597
2598 if (!warn)
2599 errors ++;
2600 }
2601
b94498cf 2602 if (!attr->value ||
1f0275e3
MS
2603 sscanf(attr->value, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
2604 &cost, program) != 4)
b94498cf 2605 {
2606 if (!warn && !errors && !verbose)
0837b7e8 2607 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 2608
2609 if (verbose >= 0)
2610 _cupsLangPrintf(stdout,
0837b7e8 2611 _(" %s Bad cupsPreFilter value \"%s\"."),
b94498cf 2612 prefix, attr->value ? attr->value : "");
2613
2614 if (!warn)
2615 errors ++;
2616 }
749b1e90 2617 else if (strcmp(program, "-"))
b94498cf 2618 {
2619 if (program[0] == '/')
2620 snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
2621 else
2622 {
2623 if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
2624 ptr = CUPS_SERVERBIN;
2625
2626 if (*ptr == '/' || !*root)
2627 snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
2628 program);
2629 else
2630 snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
2631 program);
2632 }
2633
b226ab99 2634 if (stat(pathprog, &fileinfo))
b94498cf 2635 {
2636 if (!warn && !errors && !verbose)
0837b7e8 2637 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 2638
2639 if (verbose >= 0)
84315f46
MS
2640 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2641 prefix, "cupsPreFilter", pathprog);
b94498cf 2642
2643 if (!warn)
2644 errors ++;
2645 }
b226ab99
MS
2646 else if (fileinfo.st_uid != 0 ||
2647 (fileinfo.st_mode & MODE_WRITE) ||
2648 (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
2649 {
2650 if (!warn && !errors && !verbose)
0837b7e8 2651 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
2652
2653 if (verbose >= 0)
84315f46
MS
2654 _cupsLangPrintf(stdout,
2655 _(" %s Bad permissions on %s file \"%s\"."),
2656 prefix, "cupsPreFilter", pathprog);
b226ab99
MS
2657
2658 if (!warn)
2659 errors ++;
2660 }
1340db2d
MS
2661 else
2662 errors = valid_path("cupsPreFilter", pathprog, errors, verbose, warn);
2663 }
2664 }
2665
2666#ifdef __APPLE__
2667 /*
2668 * APDialogExtension
2669 */
2670
88f9aafc
MS
2671 for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL);
2672 attr != NULL;
1340db2d
MS
2673 attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
2674 {
8b116e60
MS
2675 if (strcmp(attr->name, "APDialogExtension"))
2676 {
2677 if (!warn && !errors && !verbose)
0837b7e8 2678 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2679
2680 if (verbose >= 0)
2681 _cupsLangPrintf(stdout,
0837b7e8 2682 _(" %s Bad spelling of %s - should be %s."),
8b116e60
MS
2683 prefix, attr->name, "APDialogExtension");
2684
2685 if (!warn)
2686 errors ++;
2687 }
88f9aafc 2688
b226ab99
MS
2689 snprintf(pathprog, sizeof(pathprog), "%s%s", root,
2690 attr->value ? attr->value : "(null)");
8b116e60 2691
b226ab99 2692 if (!attr->value || stat(pathprog, &fileinfo))
1340db2d
MS
2693 {
2694 if (!warn && !errors && !verbose)
0837b7e8 2695 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
2696
2697 if (verbose >= 0)
84315f46
MS
2698 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2699 prefix, "APDialogExtension", pathprog);
b226ab99
MS
2700
2701 if (!warn)
2702 errors ++;
2703 }
2704 else if (fileinfo.st_uid != 0 ||
2705 (fileinfo.st_mode & MODE_WRITE) ||
2706 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
2707 {
2708 if (!warn && !errors && !verbose)
0837b7e8 2709 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
2710
2711 if (verbose >= 0)
84315f46
MS
2712 _cupsLangPrintf(stdout,
2713 _(" %s Bad permissions on %s file \"%s\"."),
2714 prefix, "APDialogExtension", pathprog);
1340db2d
MS
2715
2716 if (!warn)
2717 errors ++;
2718 }
2719 else
b226ab99 2720 errors = valid_path("APDialogExtension", pathprog, errors, verbose,
1340db2d
MS
2721 warn);
2722 }
2723
2724 /*
2725 * APPrinterIconPath
2726 */
2727
2728 if ((attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
2729 {
8b116e60
MS
2730 if (strcmp(attr->name, "APPrinterIconPath"))
2731 {
2732 if (!warn && !errors && !verbose)
0837b7e8 2733 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2734
2735 if (verbose >= 0)
2736 _cupsLangPrintf(stdout,
0837b7e8 2737 _(" %s Bad spelling of %s - should be %s."),
8b116e60
MS
2738 prefix, attr->name, "APPrinterIconPath");
2739
2740 if (!warn)
2741 errors ++;
2742 }
2743
b226ab99
MS
2744 snprintf(pathprog, sizeof(pathprog), "%s%s", root,
2745 attr->value ? attr->value : "(null)");
2746
2747 if (!attr->value || stat(pathprog, &fileinfo))
1340db2d
MS
2748 {
2749 if (!warn && !errors && !verbose)
0837b7e8 2750 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
2751
2752 if (verbose >= 0)
84315f46
MS
2753 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2754 prefix, "APPrinterIconPath", pathprog);
b226ab99
MS
2755
2756 if (!warn)
2757 errors ++;
2758 }
2759 else if (fileinfo.st_uid != 0 ||
2760 (fileinfo.st_mode & MODE_WRITE) ||
2761 (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
2762 {
2763 if (!warn && !errors && !verbose)
0837b7e8 2764 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
2765
2766 if (verbose >= 0)
84315f46
MS
2767 _cupsLangPrintf(stdout,
2768 _(" %s Bad permissions on %s file \"%s\"."),
2769 prefix, "APPrinterIconPath", pathprog);
1340db2d
MS
2770
2771 if (!warn)
2772 errors ++;
2773 }
2774 else
b226ab99 2775 errors = valid_path("APPrinterIconPath", pathprog, errors, verbose,
1340db2d
MS
2776 warn);
2777 }
2778
2779 /*
2780 * APPrinterLowInkTool
2781 */
2782
2783 if ((attr = ppdFindAttr(ppd, "APPrinterLowInkTool", NULL)) != NULL)
2784 {
8b116e60
MS
2785 if (strcmp(attr->name, "APPrinterLowInkTool"))
2786 {
2787 if (!warn && !errors && !verbose)
0837b7e8 2788 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2789
2790 if (verbose >= 0)
2791 _cupsLangPrintf(stdout,
0837b7e8 2792 _(" %s Bad spelling of %s - should be %s."),
8b116e60
MS
2793 prefix, attr->name, "APPrinterLowInkTool");
2794
2795 if (!warn)
2796 errors ++;
2797 }
2798
b226ab99
MS
2799 snprintf(pathprog, sizeof(pathprog), "%s%s", root,
2800 attr->value ? attr->value : "(null)");
2801
2802 if (!attr->value || stat(pathprog, &fileinfo))
1340db2d
MS
2803 {
2804 if (!warn && !errors && !verbose)
0837b7e8 2805 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
2806
2807 if (verbose >= 0)
84315f46
MS
2808 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2809 prefix, "APPrinterLowInkTool", pathprog);
b226ab99
MS
2810
2811 if (!warn)
2812 errors ++;
2813 }
2814 else if (fileinfo.st_uid != 0 ||
2815 (fileinfo.st_mode & MODE_WRITE) ||
2816 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
2817 {
2818 if (!warn && !errors && !verbose)
0837b7e8 2819 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
2820
2821 if (verbose >= 0)
84315f46
MS
2822 _cupsLangPrintf(stdout,
2823 _(" %s Bad permissions on %s file \"%s\"."),
2824 prefix, "APPrinterLowInkTool", pathprog);
1340db2d
MS
2825
2826 if (!warn)
2827 errors ++;
2828 }
2829 else
b226ab99 2830 errors = valid_path("APPrinterLowInkTool", pathprog, errors, verbose,
1340db2d
MS
2831 warn);
2832 }
2833
2834 /*
2835 * APPrinterUtilityPath
2836 */
2837
2838 if ((attr = ppdFindAttr(ppd, "APPrinterUtilityPath", NULL)) != NULL)
2839 {
8b116e60
MS
2840 if (strcmp(attr->name, "APPrinterUtilityPath"))
2841 {
2842 if (!warn && !errors && !verbose)
0837b7e8 2843 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2844
2845 if (verbose >= 0)
2846 _cupsLangPrintf(stdout,
0837b7e8 2847 _(" %s Bad spelling of %s - should be %s."),
8b116e60
MS
2848 prefix, attr->name, "APPrinterUtilityPath");
2849
2850 if (!warn)
2851 errors ++;
2852 }
2853
b226ab99
MS
2854 snprintf(pathprog, sizeof(pathprog), "%s%s", root,
2855 attr->value ? attr->value : "(null)");
2856
2857 if (!attr->value || stat(pathprog, &fileinfo))
1340db2d
MS
2858 {
2859 if (!warn && !errors && !verbose)
0837b7e8 2860 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
2861
2862 if (verbose >= 0)
84315f46
MS
2863 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2864 prefix, "APPrinterUtilityPath", pathprog);
b226ab99
MS
2865
2866 if (!warn)
2867 errors ++;
2868 }
2869 else if (fileinfo.st_uid != 0 ||
2870 (fileinfo.st_mode & MODE_WRITE) ||
2871 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
2872 {
2873 if (!warn && !errors && !verbose)
0837b7e8 2874 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
2875
2876 if (verbose >= 0)
84315f46
MS
2877 _cupsLangPrintf(stdout,
2878 _(" %s Bad permissions on %s file \"%s\"."),
2879 prefix, "APPrinterUtilityPath", pathprog);
1340db2d
MS
2880
2881 if (!warn)
2882 errors ++;
b94498cf 2883 }
1340db2d 2884 else
b226ab99 2885 errors = valid_path("APPrinterUtilityPath", pathprog, errors, verbose,
1340db2d 2886 warn);
b94498cf 2887 }
8b116e60
MS
2888
2889 /*
2890 * APScanAppBundleID and APScanAppPath
2891 */
2892
2893 if ((attr = ppdFindAttr(ppd, "APScanAppPath", NULL)) != NULL)
2894 {
2895 if (strcmp(attr->name, "APScanAppPath"))
2896 {
2897 if (!warn && !errors && !verbose)
0837b7e8 2898 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2899
2900 if (verbose >= 0)
2901 _cupsLangPrintf(stdout,
0837b7e8 2902 _(" %s Bad spelling of %s - should be %s."),
8b116e60
MS
2903 prefix, attr->name, "APScanAppPath");
2904
2905 if (!warn)
2906 errors ++;
2907 }
2908
b226ab99 2909 if (!attr->value || stat(attr->value, &fileinfo))
8b116e60
MS
2910 {
2911 if (!warn && !errors && !verbose)
0837b7e8 2912 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2913
2914 if (verbose >= 0)
84315f46
MS
2915 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
2916 prefix, "APScanAppPath",
2917 attr->value ? attr->value : "<NULL>");
8b116e60
MS
2918
2919 if (!warn)
2920 errors ++;
2921 }
b226ab99
MS
2922 else if (fileinfo.st_uid != 0 ||
2923 (fileinfo.st_mode & MODE_WRITE) ||
2924 (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
2925 {
2926 if (!warn && !errors && !verbose)
0837b7e8 2927 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
2928
2929 if (verbose >= 0)
84315f46
MS
2930 _cupsLangPrintf(stdout,
2931 _(" %s Bad permissions on %s file \"%s\"."),
2932 prefix, "APScanAppPath", attr->value);
b226ab99
MS
2933
2934 if (!warn)
2935 errors ++;
2936 }
8b116e60
MS
2937 else
2938 errors = valid_path("APScanAppPath", attr->value, errors, verbose,
2939 warn);
2940
2941 if (ppdFindAttr(ppd, "APScanAppBundleID", NULL))
2942 {
2943 if (!warn && !errors && !verbose)
0837b7e8 2944 _cupsLangPuts(stdout, _(" FAIL"));
8b116e60
MS
2945
2946 if (verbose >= 0)
2947 _cupsLangPrintf(stdout, _(" %s Cannot provide both "
0837b7e8 2948 "APScanAppPath and APScanAppBundleID."),
8b116e60
MS
2949 prefix);
2950
2951 if (!warn)
2952 errors ++;
2953 }
2954 }
1340db2d 2955#endif /* __APPLE__ */
b94498cf 2956
2957 return (errors);
2958}
2959
2960
a603edef
MS
2961/*
2962 * 'check_profiles()' - Check ICC color profiles in the PPD file.
2963 */
2964
2965static int /* O - Errors found */
2966check_profiles(ppd_file_t *ppd, /* I - PPD file */
2967 const char *root, /* I - Root directory */
2968 int errors, /* I - Errors found */
2969 int verbose, /* I - Verbosity level */
2970 int warn) /* I - Warnings only? */
2971{
2972 int i; /* Looping var */
2973 ppd_attr_t *attr; /* PPD attribute */
2974 const char *ptr; /* Pointer into string */
2975 const char *prefix; /* WARN/FAIL prefix */
2976 char filename[1024]; /* Profile filename */
b226ab99 2977 struct stat fileinfo; /* File information */
a603edef
MS
2978 int num_profiles = 0; /* Number of profiles */
2979 unsigned hash, /* Current hash value */
2980 hashes[1000]; /* Hash values of profile names */
2981 const char *specs[1000]; /* Specifiers for profiles */
2982
2983
2984 prefix = warn ? " WARN " : "**FAIL**";
2985
2986 for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
2987 attr;
2988 attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
2989 {
2990 /*
2991 * Check for valid selector...
2992 */
2993
2994 for (i = 0, ptr = strchr(attr->spec, '.'); ptr; ptr = strchr(ptr + 1, '.'))
2995 i ++;
2996
2997 if (!attr->value || i < 2)
2998 {
2999 if (!warn && !errors && !verbose)
0837b7e8 3000 _cupsLangPuts(stdout, _(" FAIL"));
a603edef
MS
3001
3002 if (verbose >= 0)
3003 _cupsLangPrintf(stdout,
0837b7e8 3004 _(" %s Bad cupsICCProfile %s."),
a603edef
MS
3005 prefix, attr->spec);
3006
3007 if (!warn)
3008 errors ++;
3009
3010 continue;
3011 }
3012
3013 /*
3014 * Check for valid profile filename...
3015 */
3016
3017 if (attr->value[0] == '/')
3018 snprintf(filename, sizeof(filename), "%s%s", root, attr->value);
3019 else
3020 {
3021 if ((ptr = getenv("CUPS_DATADIR")) == NULL)
3022 ptr = CUPS_DATADIR;
3023
3024 if (*ptr == '/' || !*root)
3025 snprintf(filename, sizeof(filename), "%s%s/profiles/%s", root, ptr,
3026 attr->value);
3027 else
3028 snprintf(filename, sizeof(filename), "%s/%s/profiles/%s", root, ptr,
3029 attr->value);
3030 }
3031
b226ab99 3032 if (stat(filename, &fileinfo))
a603edef
MS
3033 {
3034 if (!warn && !errors && !verbose)
0837b7e8 3035 _cupsLangPuts(stdout, _(" FAIL"));
a603edef
MS
3036
3037 if (verbose >= 0)
84315f46
MS
3038 _cupsLangPrintf(stdout, _(" %s Missing %s file \"%s\"."),
3039 prefix, "cupsICCProfile", filename);
b226ab99
MS
3040
3041 if (!warn)
3042 errors ++;
3043 }
3044 else if (fileinfo.st_uid != 0 ||
3045 (fileinfo.st_mode & MODE_WRITE) ||
3046 (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
3047 {
3048 if (!warn && !errors && !verbose)
0837b7e8 3049 _cupsLangPuts(stdout, _(" FAIL"));
b226ab99
MS
3050
3051 if (verbose >= 0)
84315f46
MS
3052 _cupsLangPrintf(stdout,
3053 _(" %s Bad permissions on %s file \"%s\"."),
3054 prefix, "cupsICCProfile", filename);
a603edef
MS
3055
3056 if (!warn)
3057 errors ++;
3058 }
1340db2d
MS
3059 else
3060 errors = valid_path("cupsICCProfile", filename, errors, verbose, warn);
a603edef
MS
3061
3062 /*
3063 * Check for hash collisions...
3064 */
3065
3066 hash = _ppdHashName(attr->spec);
3067
3068 if (num_profiles > 0)
3069 {
3070 for (i = 0; i < num_profiles; i ++)
3071 if (hashes[i] == hash)
3072 break;
3073
3074 if (i < num_profiles)
3075 {
3076 if (!warn && !errors && !verbose)
0837b7e8 3077 _cupsLangPuts(stdout, _(" FAIL"));
a603edef
MS
3078
3079 if (verbose >= 0)
3080 _cupsLangPrintf(stdout,
3081 _(" %s cupsICCProfile %s hash value "
0837b7e8 3082 "collides with %s."), prefix, attr->spec,
a603edef
MS
3083 specs[i]);
3084
3085 if (!warn)
3086 errors ++;
3087 }
3088 }
3089
3090 /*
3091 * Remember up to 1000 profiles...
3092 */
3093
3094 if (num_profiles < 1000)
3095 {
3096 hashes[num_profiles] = hash;
3097 specs[num_profiles] = attr->spec;
3098 num_profiles ++;
3099 }
3100 }
3101
3102 return (errors);
3103}
3104
3105
1340db2d
MS
3106/*
3107 * 'check_sizes()' - Check media sizes in the PPD file.
3108 */
3109
3110static int /* O - Errors found */
3111check_sizes(ppd_file_t *ppd, /* I - PPD file */
3112 int errors, /* I - Errors found */
3113 int verbose, /* I - Verbosity level */
3114 int warn) /* I - Warnings only? */
3115{
22c9029b 3116 int i; /* Looping var */
1340db2d
MS
3117 ppd_size_t *size; /* Current size */
3118 int width, /* Custom width */
3119 length; /* Custom length */
1340db2d
MS
3120 const char *prefix; /* WARN/FAIL prefix */
3121 ppd_option_t *page_size, /* PageSize option */
3122 *page_region; /* PageRegion option */
788d7a15 3123 pwg_media_t *pwg_media; /* PWG media */
c1420c87 3124 char buf[PPD_MAX_NAME]; /* PapeSize name that is supposed to be */
22c9029b
MS
3125 const char *ptr; /* Pointer into string */
3126 int width_2540ths, /* PageSize width in 2540ths */
3127 length_2540ths; /* PageSize length in 2540ths */
3128 int is_ok; /* Flag for PageSize name verification */
3129 double width_tmp, /* Width after rounded up */
3130 length_tmp, /* Length after rounded up */
3131 width_inch, /* Width in inches */
3132 length_inch, /* Length in inches */
3133 width_mm, /* Width in millimeters */
3134 length_mm; /* Length in millimeters */
1340db2d
MS
3135
3136
3137 prefix = warn ? " WARN " : "**FAIL**";
3138
3139 if ((page_size = ppdFindOption(ppd, "PageSize")) == NULL && warn != 2)
3140 {
3141 if (!warn && !errors && !verbose)
0837b7e8 3142 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
3143
3144 if (verbose >= 0)
3145 _cupsLangPrintf(stdout,
0837b7e8
MS
3146 _(" %s Missing REQUIRED PageSize option.\n"
3147 " REF: Page 99, section 5.14."),
1340db2d
MS
3148 prefix);
3149
3150 if (!warn)
3151 errors ++;
3152 }
3153
3154 if ((page_region = ppdFindOption(ppd, "PageRegion")) == NULL && warn != 2)
3155 {
3156 if (!warn && !errors && !verbose)
0837b7e8 3157 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
3158
3159 if (verbose >= 0)
3160 _cupsLangPrintf(stdout,
0837b7e8
MS
3161 _(" %s Missing REQUIRED PageRegion option.\n"
3162 " REF: Page 100, section 5.14."),
1340db2d
MS
3163 prefix);
3164
3165 if (!warn)
3166 errors ++;
3167 }
3168
3169 for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
3170 {
3171 /*
3172 * Check that the size name is standard...
3173 */
3174
3175 if (!strcmp(size->name, "Custom"))
3176 {
3177 /*
3178 * Skip custom page size...
3179 */
3180
3181 continue;
3182 }
82cc1f9a
MS
3183
3184 if (warn != 2 && size->name[0] == 'w' &&
3185 sscanf(size->name, "w%dh%d", &width, &length) == 2)
1340db2d
MS
3186 {
3187 /*
3188 * Validate device-specific size wNNNhNNN should have proper width and
3189 * length...
3190 */
3191
3192 if (fabs(width - size->width) >= 1.0 ||
3193 fabs(length - size->length) >= 1.0)
3194 {
3195 if (!warn && !errors && !verbose)
0837b7e8 3196 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
3197
3198 if (verbose >= 0)
3199 _cupsLangPrintf(stdout,
3200 _(" %s Size \"%s\" has unexpected dimensions "
0837b7e8 3201 "(%gx%g)."),
1340db2d
MS
3202 prefix, size->name, size->width, size->length);
3203
3204 if (!warn)
3205 errors ++;
3206 }
3207 }
1340db2d
MS
3208
3209 /*
3210 * Verify that the size is defined for both PageSize and PageRegion...
3211 */
3212
3213 if (warn != 2 && !ppdFindChoice(page_size, size->name))
3214 {
3215 if (!warn && !errors && !verbose)
0837b7e8 3216 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
3217
3218 if (verbose >= 0)
3219 _cupsLangPrintf(stdout,
3220 _(" %s Size \"%s\" defined for %s but not for "
0837b7e8 3221 "%s."),
1340db2d
MS
3222 prefix, size->name, "PageRegion", "PageSize");
3223
3224 if (!warn)
3225 errors ++;
3226 }
3227 else if (warn != 2 && !ppdFindChoice(page_region, size->name))
3228 {
3229 if (!warn && !errors && !verbose)
0837b7e8 3230 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
3231
3232 if (verbose >= 0)
3233 _cupsLangPrintf(stdout,
3234 _(" %s Size \"%s\" defined for %s but not for "
0837b7e8 3235 "%s."),
1340db2d
MS
3236 prefix, size->name, "PageSize", "PageRegion");
3237
3238 if (!warn)
3239 errors ++;
3240 }
22c9029b
MS
3241
3242 /*
3243 * Verify that the size name is Adobe standard name if it's a standard size
d7225fc2 3244 * and the dimentional name if it's not a standard size. Suffix should be
22c9029b
MS
3245 * .Fullbleed, etc., or numeric, e.g., Letter, Letter.Fullbleed,
3246 * Letter.Transverse, Letter1, Letter2, 4x8, 55x91mm, 55x91mm.Fullbleed, etc.
3247 */
3248
3249 if (warn != 0)
3250 {
3251 is_ok = 1;
3252 width_2540ths = (size->length > size->width) ?
6961465f
MS
3253 PWG_FROM_POINTS(size->width) :
3254 PWG_FROM_POINTS(size->length);
22c9029b 3255 length_2540ths = (size->length > size->width) ?
6961465f
MS
3256 PWG_FROM_POINTS(size->length) :
3257 PWG_FROM_POINTS(size->width);
94436c5a 3258 pwg_media = pwgMediaForSize(width_2540ths, length_2540ths);
22c9029b 3259
c1420c87 3260 if (pwg_media &&
6884f8da
MS
3261 (abs(pwg_media->width - width_2540ths) > 34 ||
3262 abs(pwg_media->length - length_2540ths) > 34))
c1420c87
MS
3263 pwg_media = NULL; /* Only flag matches within a point */
3264
a469f8a5
MS
3265 if (pwg_media && pwg_media->ppd &&
3266 (pwg_media->ppd[0] < 'a' || pwg_media->ppd[0] > 'z'))
22c9029b 3267 {
d7225fc2
MS
3268 size_t ppdlen = strlen(pwg_media->ppd);
3269 /* Length of standard PPD name */
3270
22c9029b
MS
3271 strlcpy(buf, pwg_media->ppd, sizeof(buf));
3272
f3c17241
MS
3273 if (strcmp(size->name, buf) && size->width > size->length)
3274 {
3275 if (!strcmp(pwg_media->ppd, "DoublePostcardRotated"))
3276 strlcpy(buf, "DoublePostcard", sizeof(buf));
3277 else if (strstr(size->name, ".Transverse"))
3278 snprintf(buf, sizeof(buf), "%s.Transverse", pwg_media->ppd);
3279 else
3280 snprintf(buf, sizeof(buf), "%sRotated", pwg_media->ppd);
c1420c87
MS
3281
3282 ppdlen = strlen(buf);
f3c17241
MS
3283 }
3284
22c9029b
MS
3285 if (size->left == 0 && size->bottom == 0 &&
3286 size->right == size->width && size->top == size->length)
3287 {
f3c17241 3288 strlcat(buf, ".Fullbleed", sizeof(buf) - strlen(buf));
d7225fc2 3289 if (_cups_strcasecmp(size->name, buf))
22c9029b 3290 {
d7225fc2
MS
3291 /*
3292 * Allow an additional qualifier such as ".WithTab"...
3293 */
3294
3295 size_t buflen = strlen(buf);/* Length of full bleed name */
3296
3297 if (_cups_strncasecmp(size->name, buf, buflen) ||
3298 size->name[buflen] != '.')
22c9029b
MS
3299 is_ok = 0;
3300 }
d7225fc2 3301 }
d7225fc2
MS
3302 else if (!strncmp(size->name, pwg_media->ppd, ppdlen))
3303 {
3304 /*
3305 * Check for a proper qualifier (number, "Small", or .something)...
3306 */
3307
3308 ptr = size->name + ppdlen;
3309
3310 if (isdigit(*ptr & 255))
22c9029b 3311 {
d7225fc2 3312 for (ptr ++; *ptr; ptr ++)
22c9029b
MS
3313 {
3314 if (!isdigit(*ptr & 255))
3315 {
3316 is_ok = 0;
3317 break;
3318 }
3319 }
3320 }
d7225fc2
MS
3321 else if (*ptr != '.' && *ptr && strcmp(ptr, "Small"))
3322 is_ok = 0;
22c9029b 3323 }
d7225fc2
MS
3324 else
3325 {
3326 /*
3327 * Check for EnvSizeName as well...
3328 */
3329
a469f8a5
MS
3330 if (strncmp(pwg_media->ppd, "Env", 3) &&
3331 !strncmp(size->name, "Env", 3))
82cc1f9a 3332 snprintf(buf, sizeof(buf), "Env%s", pwg_media->ppd);
d7225fc2
MS
3333
3334 if (strcmp(size->name, buf))
3335 is_ok = 0;
3336 }
88f9aafc 3337
22c9029b
MS
3338 if (!is_ok)
3339 _cupsLangPrintf(stdout,
3340 _(" %s Size \"%s\" should be the Adobe "
3341 "standard name \"%s\"."),
3342 prefix, size->name, buf);
3343 }
3344 else
3345 {
3346 width_tmp = (fabs(size->width - ceil(size->width)) < 0.1) ?
3347 ceil(size->width) : size->width;
3348 length_tmp = (fabs(size->length - ceil(size->length)) < 0.1) ?
3349 ceil(size->length) : size->length;
3350
c1420c87 3351 if (fmod(width_tmp, 9.0) == 0.0 && fmod(length_tmp, 9.0) == 0.0)
22c9029b
MS
3352 {
3353 width_inch = width_tmp / 72.0;
3354 length_inch = length_tmp / 72.0;
3355
3356 snprintf(buf, sizeof(buf), "%gx%g", width_inch, length_inch);
3357 }
3358 else
3359 {
3360 width_mm = size->width / 72.0 * 25.4;
3361 length_mm = size->length / 72.0 * 25.4;
3362
3363 snprintf(buf, sizeof(buf), "%.0fx%.0fmm", width_mm, length_mm);
3364 }
3365
3366 if (size->left == 0 && size->bottom == 0 &&
3367 size->right == size->width && size->top == size->length)
3368 strlcat(buf, ".Fullbleed", sizeof(buf));
3369 else if (size->width > size->length)
3370 strlcat(buf, ".Transverse", sizeof(buf));
3371
d7225fc2
MS
3372 if (_cups_strcasecmp(size->name, buf))
3373 {
c1420c87
MS
3374 size_t buflen = strlen(buf);
3375 /* Length of proposed name */
d7225fc2
MS
3376
3377 if (_cups_strncasecmp(size->name, buf, buflen) ||
f3c17241
MS
3378 (strcmp(size->name + buflen, "in") &&
3379 size->name[buflen] != '.'))
c1420c87
MS
3380 {
3381 char altbuf[PPD_MAX_NAME];
3382 /* Alternate "wNNNhNNN" name */
3383 size_t altlen; /* Length of alternate name */
3384
3385 snprintf(altbuf, sizeof(altbuf), "w%.0fh%.0f", size->width,
3386 size->length);
3387 altlen = strlen(altbuf);
3388 if (_cups_strncasecmp(size->name, altbuf, altlen) ||
3389 (size->name[altlen] && size->name[altlen] != '.'))
3390 _cupsLangPrintf(stdout,
3391 _(" %s Size \"%s\" should be \"%s\"."),
3392 prefix, size->name, buf);
3393 }
d7225fc2 3394 }
22c9029b
MS
3395 }
3396 }
1340db2d
MS
3397 }
3398
3399 return (errors);
3400}
3401
3402
b94498cf 3403/*
3404 * 'check_translations()' - Check translations in the PPD file.
3405 */
3406
3d8365b8 3407static int /* O - Errors found */
b94498cf 3408check_translations(ppd_file_t *ppd, /* I - PPD file */
3409 int errors, /* I - Errors found */
3410 int verbose, /* I - Verbosity level */
3411 int warn) /* I - Warnings only? */
3412{
3413 int j; /* Looping var */
3414 ppd_attr_t *attr; /* PPD attribute */
a603edef
MS
3415 cups_array_t *languages; /* Array of languages */
3416 int langlen; /* Length of language */
3417 char *language, /* Current language */
b94498cf 3418 keyword[PPD_MAX_NAME], /* Localization keyword (full) */
3419 llkeyword[PPD_MAX_NAME],/* Localization keyword (base) */
3420 ckeyword[PPD_MAX_NAME], /* Custom option keyword (full) */
3421 cllkeyword[PPD_MAX_NAME];
3422 /* Custom option keyword (base) */
3423 ppd_option_t *option; /* Standard UI option */
3424 ppd_coption_t *coption; /* Custom option */
3425 ppd_cparam_t *cparam; /* Custom parameter */
b94498cf 3426 char ll[3]; /* Base language */
3427 const char *prefix; /* WARN/FAIL prefix */
749b1e90 3428 const char *text; /* Pointer into UI text */
b94498cf 3429
3430
3431 prefix = warn ? " WARN " : "**FAIL**";
3432
a603edef 3433 if ((languages = _ppdGetLanguages(ppd)) != NULL)
b94498cf 3434 {
3435 /*
3436 * This file contains localizations, check them...
3437 */
3438
a603edef
MS
3439 for (language = (char *)cupsArrayFirst(languages);
3440 language;
3441 language = (char *)cupsArrayNext(languages))
b94498cf 3442 {
7a0cbd5e 3443 langlen = (int)strlen(language);
a603edef 3444 if (langlen != 2 && langlen != 5)
b94498cf 3445 {
3446 if (!warn && !errors && !verbose)
0837b7e8 3447 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3448
3449 if (verbose >= 0)
3450 _cupsLangPrintf(stdout,
0837b7e8 3451 _(" %s Bad language \"%s\"."),
a603edef 3452 prefix, language);
b94498cf 3453
3454 if (!warn)
3455 errors ++;
3456
3457 continue;
3458 }
3459
a603edef 3460 if (!strcmp(language, "en"))
0a682745
MS
3461 continue;
3462
a603edef 3463 strlcpy(ll, language, sizeof(ll));
b94498cf 3464
3465 /*
3466 * Loop through all options and choices...
3467 */
3468
3469 for (option = ppdFirstOption(ppd);
3470 option;
3471 option = ppdNextOption(ppd))
3472 {
09a101d6 3473 if (!strcmp(option->keyword, "PageRegion"))
3474 continue;
3475
a603edef 3476 snprintf(keyword, sizeof(keyword), "%s.Translation", language);
b94498cf 3477 snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll);
3478
3479 if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL &&
3480 (attr = ppdFindAttr(ppd, llkeyword, option->keyword)) == NULL)
3481 {
3482 if (!warn && !errors && !verbose)
0837b7e8 3483 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3484
3485 if (verbose >= 0)
3486 _cupsLangPrintf(stdout,
3487 _(" %s Missing \"%s\" translation "
0837b7e8 3488 "string for option %s."),
a603edef 3489 prefix, language, option->keyword);
b94498cf 3490
3491 if (!warn)
3492 errors ++;
3493 }
3494 else if (!valid_utf8(attr->text))
3495 {
3496 if (!warn && !errors && !verbose)
0837b7e8 3497 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3498
3499 if (verbose >= 0)
3500 _cupsLangPrintf(stdout,
3501 _(" %s Bad UTF-8 \"%s\" translation "
0837b7e8 3502 "string for option %s."),
a603edef 3503 prefix, language, option->keyword);
b94498cf 3504
3505 if (!warn)
3506 errors ++;
3507 }
3508
a603edef 3509 snprintf(keyword, sizeof(keyword), "%s.%s", language,
b94498cf 3510 option->keyword);
3511 snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll,
3512 option->keyword);
3513
3514 for (j = 0; j < option->num_choices; j ++)
3515 {
749b1e90
MS
3516 /*
3517 * First see if this choice is a number; if so, don't require
3518 * translation...
3519 */
3520
3521 for (text = option->choices[j].text; *text; text ++)
3522 if (!strchr("0123456789-+.", *text))
3523 break;
3524
3525 if (!*text)
3526 continue;
3527
3528 /*
3529 * Check custom choices differently...
3530 */
3531
88f9aafc 3532 if (!_cups_strcasecmp(option->choices[j].choice, "Custom") &&
b94498cf 3533 (coption = ppdFindCustomOption(ppd,
3534 option->keyword)) != NULL)
3535 {
3536 snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
a603edef 3537 language, option->keyword);
b94498cf 3538
3539 if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
3540 !valid_utf8(attr->text))
3541 {
3542 if (!warn && !errors && !verbose)
0837b7e8 3543 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3544
3545 if (verbose >= 0)
3546 _cupsLangPrintf(stdout,
3547 _(" %s Bad UTF-8 \"%s\" "
3548 "translation string for option %s, "
0837b7e8 3549 "choice %s."),
a603edef
MS
3550 prefix, language,
3551 ckeyword + 1 + strlen(language),
b94498cf 3552 "True");
3553
3554 if (!warn)
3555 errors ++;
3556 }
3557
88f9aafc 3558 if (_cups_strcasecmp(option->keyword, "PageSize"))
b94498cf 3559 {
3560 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
3561 cparam;
3562 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
3563 {
3564 snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
a603edef 3565 language, option->keyword);
b94498cf 3566 snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s",
3567 ll, option->keyword);
3568
3569 if ((attr = ppdFindAttr(ppd, ckeyword,
3570 cparam->name)) == NULL &&
3571 (attr = ppdFindAttr(ppd, cllkeyword,
3572 cparam->name)) == NULL)
3573 {
3574 if (!warn && !errors && !verbose)
0837b7e8 3575 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3576
3577 if (verbose >= 0)
3578 _cupsLangPrintf(stdout,
3579 _(" %s Missing \"%s\" "
3580 "translation string for option %s, "
0837b7e8 3581 "choice %s."),
a603edef
MS
3582 prefix, language,
3583 ckeyword + 1 + strlen(language),
b94498cf 3584 cparam->name);
3585
3586 if (!warn)
3587 errors ++;
3588 }
3589 else if (!valid_utf8(attr->text))
3590 {
3591 if (!warn && !errors && !verbose)
0837b7e8 3592 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3593
3594 if (verbose >= 0)
3595 _cupsLangPrintf(stdout,
3596 _(" %s Bad UTF-8 \"%s\" "
3597 "translation string for option %s, "
0837b7e8 3598 "choice %s."),
a603edef
MS
3599 prefix, language,
3600 ckeyword + 1 + strlen(language),
b94498cf 3601 cparam->name);
3602
3603 if (!warn)
3604 errors ++;
3605 }
3606 }
3607 }
3608 }
3609 else if ((attr = ppdFindAttr(ppd, keyword,
3610 option->choices[j].choice)) == NULL &&
3611 (attr = ppdFindAttr(ppd, llkeyword,
3612 option->choices[j].choice)) == NULL)
3613 {
3614 if (!warn && !errors && !verbose)
0837b7e8 3615 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3616
3617 if (verbose >= 0)
3618 _cupsLangPrintf(stdout,
3619 _(" %s Missing \"%s\" "
3620 "translation string for option %s, "
0837b7e8 3621 "choice %s."),
a603edef 3622 prefix, language, option->keyword,
b94498cf 3623 option->choices[j].choice);
3624
3625 if (!warn)
3626 errors ++;
3627 }
3628 else if (!valid_utf8(attr->text))
3629 {
3630 if (!warn && !errors && !verbose)
0837b7e8 3631 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3632
3633 if (verbose >= 0)
3634 _cupsLangPrintf(stdout,
3635 _(" %s Bad UTF-8 \"%s\" "
3636 "translation string for option %s, "
0837b7e8 3637 "choice %s."),
a603edef 3638 prefix, language, option->keyword,
b94498cf 3639 option->choices[j].choice);
3640
3641 if (!warn)
3642 errors ++;
3643 }
3644 }
3645 }
3646 }
3647
3648 /*
3649 * Verify that we have the base language for each localized one...
3650 */
3651
a603edef
MS
3652 for (language = (char *)cupsArrayFirst(languages);
3653 language;
3654 language = (char *)cupsArrayNext(languages))
3655 if (language[2])
b94498cf 3656 {
3657 /*
3658 * Lookup the base language...
3659 */
3660
a603edef 3661 cupsArraySave(languages);
b94498cf 3662
a603edef 3663 strlcpy(ll, language, sizeof(ll));
b94498cf 3664
005dd1eb
MS
3665 if (!cupsArrayFind(languages, ll) &&
3666 strcmp(ll, "zh") && strcmp(ll, "en"))
b94498cf 3667 {
3668 if (!warn && !errors && !verbose)
0837b7e8 3669 _cupsLangPuts(stdout, _(" FAIL"));
b94498cf 3670
3671 if (verbose >= 0)
3672 _cupsLangPrintf(stdout,
3673 _(" %s No base translation \"%s\" "
0837b7e8 3674 "is included in file."), prefix, ll);
b94498cf 3675
3676 if (!warn)
3677 errors ++;
3678 }
3679
a603edef 3680 cupsArrayRestore(languages);
b94498cf 3681 }
3682
3683 /*
3684 * Free memory used for the languages...
3685 */
3686
a603edef 3687 _ppdFreeLanguages(languages);
b94498cf 3688 }
3689
3690 return (errors);
3691}
3692
3693
ef416fc2 3694/*
3695 * 'show_conflicts()' - Show option conflicts in a PPD file.
3696 */
3697
3d8365b8 3698static void
22c9029b
MS
3699show_conflicts(ppd_file_t *ppd, /* I - PPD to check */
3700 const char *prefix) /* I - Prefix string */
ef416fc2 3701{
3702 int i, j; /* Looping variables */
3703 ppd_const_t *c; /* Current constraint */
3704 ppd_option_t *o1, *o2; /* Options */
3705 ppd_choice_t *c1, *c2; /* Choices */
3706
3707
3708 /*
3709 * Loop through all of the UI constraints and report any options
3710 * that conflict...
3711 */
3712
3713 for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
3714 {
3715 /*
3716 * Grab pointers to the first option...
3717 */
3718
3719 o1 = ppdFindOption(ppd, c->option1);
3720
3721 if (o1 == NULL)
3722 continue;
3723 else if (c->choice1[0] != '\0')
3724 {
3725 /*
3726 * This constraint maps to a specific choice.
3727 */
3728
3729 c1 = ppdFindChoice(o1, c->choice1);
3730 }
3731 else
3732 {
3733 /*
3734 * This constraint applies to any choice for this option.
3735 */
3736
3737 for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
3738 if (c1->marked)
3739 break;
3740
3741 if (j == 0 ||
88f9aafc
MS
3742 !_cups_strcasecmp(c1->choice, "None") ||
3743 !_cups_strcasecmp(c1->choice, "Off") ||
3744 !_cups_strcasecmp(c1->choice, "False"))
ef416fc2 3745 c1 = NULL;
3746 }
3747
3748 /*
3749 * Grab pointers to the second option...
3750 */
3751
3752 o2 = ppdFindOption(ppd, c->option2);
3753
3754 if (o2 == NULL)
3755 continue;
3756 else if (c->choice2[0] != '\0')
3757 {
3758 /*
3759 * This constraint maps to a specific choice.
3760 */
3761
3762 c2 = ppdFindChoice(o2, c->choice2);
3763 }
3764 else
3765 {
3766 /*
3767 * This constraint applies to any choice for this option.
3768 */
3769
3770 for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
3771 if (c2->marked)
3772 break;
3773
3774 if (j == 0 ||
88f9aafc
MS
3775 !_cups_strcasecmp(c2->choice, "None") ||
3776 !_cups_strcasecmp(c2->choice, "Off") ||
3777 !_cups_strcasecmp(c2->choice, "False"))
ef416fc2 3778 c2 = NULL;
3779 }
3780
3781 /*
3782 * If both options are marked then there is a conflict...
3783 */
3784
3785 if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
fa73b229 3786 _cupsLangPrintf(stdout,
22c9029b 3787 _(" %s \"%s %s\" conflicts with \"%s %s\"\n"
0837b7e8 3788 " (constraint=\"%s %s %s %s\")."),
22c9029b 3789 prefix, o1->keyword, c1->choice, o2->keyword, c2->choice,
ef416fc2 3790 c->option1, c->choice1, c->option2, c->choice2);
3791 }
3792}
3793
3794
09a101d6 3795/*
3796 * 'test_raster()' - Test PostScript commands for raster printers.
3797 */
3798
3799static int /* O - 1 on success, 0 on failure */
3800test_raster(ppd_file_t *ppd, /* I - PPD file */
3801 int verbose) /* I - Verbosity */
3802{
3803 cups_page_header2_t header; /* Page header */
3804
3805
3806 ppdMarkDefaults(ppd);
3807 if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0))
3808 {
3809 if (!verbose)
0837b7e8 3810 _cupsLangPuts(stdout, _(" FAIL"));
09a101d6 3811
3812 if (verbose >= 0)
3813 _cupsLangPrintf(stdout,
3814 _(" **FAIL** Default option code cannot be "
0837b7e8 3815 "interpreted: %s"), cupsRasterErrorString());
09a101d6 3816
3817 return (0);
3818 }
db1f069b
MS
3819
3820 /*
3821 * Try a test of custom page size code, if available...
3822 */
3823
3824 if (!ppdPageSize(ppd, "Custom.612x792"))
09a101d6 3825 return (1);
db1f069b
MS
3826
3827 ppdMarkOption(ppd, "PageSize", "Custom.612x792");
3828
3829 if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0))
3830 {
3831 if (!verbose)
0837b7e8 3832 _cupsLangPuts(stdout, _(" FAIL"));
db1f069b
MS
3833
3834 if (verbose >= 0)
3835 _cupsLangPrintf(stdout,
3836 _(" **FAIL** Default option code cannot be "
0837b7e8 3837 "interpreted: %s"), cupsRasterErrorString());
db1f069b
MS
3838
3839 return (0);
3840 }
3841
3842 return (1);
09a101d6 3843}
3844
3845
ef416fc2 3846/*
22c9029b 3847 * 'usage()' - Show program usage.
ef416fc2 3848 */
3849
3d8365b8 3850static void
ef416fc2 3851usage(void)
3852{
8e52928c
MS
3853 _cupsLangPuts(stdout, _("Warning: This program will be removed in a future version of CUPS."));
3854 _cupsLangPuts(stdout, _("Usage: cupstestppd [options] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
3855 " program | cupstestppd [options] -"));
0837b7e8 3856 _cupsLangPuts(stdout, _("Options:"));
8e52928c
MS
3857 _cupsLangPuts(stdout, _("-I {filename,filters,none,profiles}\n"
3858 " Ignore specific warnings"));
3859 _cupsLangPuts(stdout, _("-R root-directory Set alternate root"));
3860 _cupsLangPuts(stdout, _("-W {all,none,constraints,defaults,duplex,filters,profiles,sizes,translations}\n"
3861 " Issue warnings instead of errors"));
3862 _cupsLangPuts(stdout, _("-q Run silently"));
3863 _cupsLangPuts(stdout, _("-r Use 'relaxed' open mode"));
3864 _cupsLangPuts(stdout, _("-v Be verbose"));
3865 _cupsLangPuts(stdout, _("-vv Be very verbose"));
ef416fc2 3866
3867 exit(ERROR_USAGE);
3868}
3869
3870
1340db2d
MS
3871/*
3872 * 'valid_path()' - Check whether a path has the correct capitalization.
3873 */
3874
3875static int /* O - Errors found */
3876valid_path(const char *keyword, /* I - Keyword using path */
3877 const char *path, /* I - Path to check */
3878 int errors, /* I - Errors found */
3879 int verbose, /* I - Verbosity level */
3880 int warn) /* I - Warnings only? */
3881{
3882 cups_dir_t *dir; /* Current directory */
3883 cups_dentry_t *dentry; /* Current directory entry */
3884 char temp[1024], /* Temporary path */
3885 *ptr; /* Pointer into temporary path */
3886 const char *prefix; /* WARN/FAIL prefix */
3887
3888
3889 prefix = warn ? " WARN " : "**FAIL**";
3890
3891 /*
3892 * Loop over the components of the path, checking that the entry exists with
3893 * the same capitalization...
3894 */
3895
3896 strlcpy(temp, path, sizeof(temp));
3897
3898 while ((ptr = strrchr(temp, '/')) != NULL)
3899 {
3900 /*
3901 * Chop off the trailing component so temp == dirname and ptr == basename.
3902 */
3903
3904 *ptr++ = '\0';
3905
3906 /*
3907 * Try opening the directory containing the base name...
3908 */
3909
3910 if (temp[0])
3911 dir = cupsDirOpen(temp);
3912 else
3913 dir = cupsDirOpen("/");
3914
3915 if (!dir)
3916 dentry = NULL;
3917 else
3918 {
3919 while ((dentry = cupsDirRead(dir)) != NULL)
3920 {
3921 if (!strcmp(dentry->filename, ptr))
3922 break;
3923 }
3924
3925 cupsDirClose(dir);
3926 }
3927
3928 /*
3929 * Display an error if the filename doesn't exist with the same
3930 * capitalization...
3931 */
3932
3933 if (!dentry)
3934 {
3935 if (!warn && !errors && !verbose)
0837b7e8 3936 _cupsLangPuts(stdout, _(" FAIL"));
1340db2d
MS
3937
3938 if (verbose >= 0)
3939 _cupsLangPrintf(stdout,
3940 _(" %s %s file \"%s\" has the wrong "
0837b7e8 3941 "capitalization."), prefix, keyword, path);
1340db2d
MS
3942
3943 if (!warn)
3944 errors ++;
3945
3946 break;
3947 }
3948 }
3949
3950 return (errors);
3951}
3952
3953
ef416fc2 3954/*
f7deaa1a 3955 * 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
3956 */
3957
3d8365b8 3958static int /* O - 1 if valid, 0 if not */
f7deaa1a 3959valid_utf8(const char *s) /* I - String to check */
3960{
3961 while (*s)
3962 {
3963 if (*s & 0x80)
3964 {
3965 /*
3966 * Check for valid UTF-8 sequence...
3967 */
3968
3969 if ((*s & 0xc0) == 0x80)
3970 return (0); /* Illegal suffix byte */
3971 else if ((*s & 0xe0) == 0xc0)
3972 {
3973 /*
3974 * 2-byte sequence...
3975 */
3976
3977 s ++;
3978
3979 if ((*s & 0xc0) != 0x80)
3980 return (0); /* Missing suffix byte */
3981 }
3982 else if ((*s & 0xf0) == 0xe0)
3983 {
3984 /*
3985 * 3-byte sequence...
3986 */
3987
3988 s ++;
3989
3990 if ((*s & 0xc0) != 0x80)
3991 return (0); /* Missing suffix byte */
3992
3993 s ++;
3994
3995 if ((*s & 0xc0) != 0x80)
3996 return (0); /* Missing suffix byte */
3997 }
3998 else if ((*s & 0xf8) == 0xf0)
3999 {
4000 /*
4001 * 4-byte sequence...
4002 */
4003
4004 s ++;
4005
4006 if ((*s & 0xc0) != 0x80)
4007 return (0); /* Missing suffix byte */
4008
4009 s ++;
4010
4011 if ((*s & 0xc0) != 0x80)
4012 return (0); /* Missing suffix byte */
4013
4014 s ++;
4015
4016 if ((*s & 0xc0) != 0x80)
4017 return (0); /* Missing suffix byte */
4018 }
4019 else
4020 return (0); /* Bad sequence */
4021 }
4022
4023 s ++;
4024 }
4025
4026 return (1);
4027}