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