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