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