/*
- * "$Id: cupstestppd.c 6430 2007-04-02 14:01:55Z mike $"
+ * "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $"
*
* PPD test program for the Common UNIX Printing System (CUPS).
*
+ * Copyright 2007-2009 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* PostScript is a trademark of Adobe Systems, Inc.
*
*
* Contents:
*
- * main() - Main entry for test program.
- * show_conflicts() - Show option conflicts in a PPD file.
- * usage() - Show program usage...
- * valid_utf8() - Check whether a string contains valid UTF-8 text.
+ * main() - Main entry for test program.
+ * check_basics() - Check for CR LF, mixed line endings, and blank
+ * lines.
+ * check_constraints() - Check UIConstraints in the PPD file.
+ * check_case() - Check that there are no duplicate groups, options,
+ * or choices that differ only by case.
+ * check_defaults() - Check default option keywords in the PPD file.
+ * check_duplex() - Check duplex keywords in the PPD file.
+ * check_filters() - Check filters in the PPD file.
+ * check_profiles() - Check ICC color profiles in the PPD file.
+ * check_sizes() - Check media sizes in the PPD file.
+ * check_translations() - Check translations in the PPD file.
+ * show_conflicts() - Show option conflicts in a PPD file.
+ * test_raster() - Test PostScript commands for raster printers.
+ * usage() - Show program usage...
+ * valid_path() - Check whether a path has the correct capitalization.
+ * valid_utf8() - Check whether a string contains valid UTF-8 text.
*/
/*
#include <cups/string.h>
#include <cups/cups.h>
+#include <cups/dir.h>
+#include <cups/ppd-private.h>
#include <cups/i18n.h>
+#include <cups/raster.h>
#include <errno.h>
#include <stdlib.h>
+#include <math.h>
+#ifdef WIN32
+# define X_OK 0
+#endif /* WIN32 */
+
+
+/*
+ * Error warning overrides...
+ */
+
+enum
+{
+ WARN_NONE = 0,
+ WARN_CONSTRAINTS = 1,
+ WARN_DEFAULTS = 2,
+ WARN_FILTERS = 4,
+ WARN_PROFILES = 8,
+ WARN_TRANSLATIONS = 16,
+ WARN_DUPLEX = 32,
+ WARN_SIZES = 64,
+ WARN_ALL = 127
+};
/*
};
+/*
+ * File permissions...
+ */
+
+#define MODE_WRITE 0022 /* Group/other write */
+#define MODE_MASK 0555 /* Owner/group/other read+exec/search */
+#define MODE_DATAFILE 0444 /* Owner/group/other read */
+#define MODE_DIRECTORY 0555 /* Owner/group/other read+search */
+#define MODE_PROGRAM 0555 /* Owner/group/other read+exec */
+
+
+/*
+ * Standard Adobe media keywords (must remain sorted)...
+ */
+
+static const char adobe_size_names[][PPD_MAX_NAME] =
+{
+ "10x11",
+ "10x13",
+ "10x14",
+ "12x11",
+ "15x11",
+ "7x9",
+ "8x10",
+ "9x11",
+ "9x12",
+ "A0",
+ "A1",
+ "A10",
+ "A2",
+ "A3",
+ "A3Extra",
+ "A3Rotated",
+ "A4",
+ "A4Extra",
+ "A4Plus",
+ "A4Rotated",
+ "A4Small",
+ "A5",
+ "A5Extra",
+ "A5Rotated",
+ "A6",
+ "A6Rotated",
+ "A7",
+ "A8",
+ "A9",
+ "ARCHA",
+ "ARCHB",
+ "ARCHC",
+ "ARCHD",
+ "ARCHE",
+ "AnsiA",
+ "AnsiB",
+ "AnsiC",
+ "AnsiD",
+ "AnsiE",
+ "B0",
+ "B1",
+ "B1",
+ "B10",
+ "B2",
+ "B3",
+ "B4",
+ "B4Rotated",
+ "B5",
+ "B5Rotated",
+ "B6",
+ "B6Rotated",
+ "B7",
+ "B8",
+ "B9",
+ "C4",
+ "C5",
+ "C6",
+ "DL",
+ "DoublePostcard",
+ "DoublePostcardRotated",
+ "Env10",
+ "Env11",
+ "Env12",
+ "Env14",
+ "Env9",
+ "EnvC0",
+ "EnvC1",
+ "EnvC2",
+ "EnvC3",
+ "EnvC4",
+ "EnvC5",
+ "EnvC6",
+ "EnvC65",
+ "EnvC7",
+ "EnvChou3",
+ "EnvChou3Rotated",
+ "EnvChou4",
+ "EnvChou4Rotated",
+ "EnvDL",
+ "EnvISOB4",
+ "EnvISOB5",
+ "EnvISOB6",
+ "EnvInvite",
+ "EnvItalian",
+ "EnvKaku2",
+ "EnvKaku2Rotated",
+ "EnvKaku3",
+ "EnvKaku3Rotated",
+ "EnvMonarch",
+ "EnvPRC1",
+ "EnvPRC10",
+ "EnvPRC10Rotated",
+ "EnvPRC1Rotated",
+ "EnvPRC2",
+ "EnvPRC2Rotated",
+ "EnvPRC3",
+ "EnvPRC3Rotated",
+ "EnvPRC4",
+ "EnvPRC4Rotated",
+ "EnvPRC5",
+ "EnvPRC5Rotated",
+ "EnvPRC6",
+ "EnvPRC6Rotated",
+ "EnvPRC7",
+ "EnvPRC7Rotated",
+ "EnvPRC8",
+ "EnvPRC8Rotated",
+ "EnvPRC9",
+ "EnvPRC9Rotated",
+ "EnvPersonal",
+ "EnvYou4",
+ "EnvYou4Rotated",
+ "Executive",
+ "FanFoldGerman",
+ "FanFoldGermanLegal",
+ "FanFoldUS",
+ "Folio",
+ "ISOB0",
+ "ISOB1",
+ "ISOB10",
+ "ISOB2",
+ "ISOB3",
+ "ISOB4",
+ "ISOB5",
+ "ISOB5Extra",
+ "ISOB6",
+ "ISOB7",
+ "ISOB8",
+ "ISOB9",
+ "Ledger",
+ "Legal",
+ "LegalExtra",
+ "Letter",
+ "LetterExtra",
+ "LetterPlus",
+ "LetterRotated",
+ "LetterSmall",
+ "Monarch",
+ "Note",
+ "PRC16K",
+ "PRC16KRotated",
+ "PRC32K",
+ "PRC32KBig",
+ "PRC32KBigRotated",
+ "PRC32KRotated",
+ "Postcard",
+ "PostcardRotated",
+ "Quarto",
+ "Statement",
+ "SuperA",
+ "SuperB",
+ "Tabloid",
+ "TabloidExtra"
+};
+
+
/*
* Local functions...
*/
-void check_basics(const char *filename);
-void show_conflicts(ppd_file_t *ppd);
-void usage(void);
-int valid_utf8(const char *s);
+static void check_basics(const char *filename);
+static int check_constraints(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static int check_case(ppd_file_t *ppd, int errors, int verbose);
+static int check_defaults(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static int check_duplex(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static int check_filters(ppd_file_t *ppd, const char *root, int errors,
+ int verbose, int warn);
+static int check_profiles(ppd_file_t *ppd, const char *root, int errors,
+ int verbose, int warn);
+static int check_sizes(ppd_file_t *ppd, int errors, int verbose, int warn);
+static int check_translations(ppd_file_t *ppd, int errors, int verbose,
+ int warn);
+static void show_conflicts(ppd_file_t *ppd);
+static int test_raster(ppd_file_t *ppd, int verbose);
+static void usage(void);
+static int valid_path(const char *keyword, const char *path, int errors,
+ int verbose, int warn);
+static int valid_utf8(const char *s);
+
/*
* 'main()' - Main entry for test program.
*/
-int /* O - Exit status */
-main(int argc, /* I - Number of command-line arguments */
- char *argv[]) /* I - Command-line arguments */
+int /* O - Exit status */
+main(int argc, /* I - Number of command-line args */
+ char *argv[]) /* I - Command-line arguments */
{
- int i, j, k, m, n; /* Looping vars */
- int len; /* Length of option name */
- char *opt; /* Option character */
- const char *ptr; /* Pointer into string */
- int files; /* Number of files */
- int verbose; /* Want verbose output? */
- int status; /* Exit status */
- int errors; /* Number of conformance errors */
- int ppdversion; /* PPD spec version in PPD file */
- ppd_status_t error; /* Status of ppdOpen*() */
- int line; /* Line number for error */
- int xdpi, /* X resolution */
- ydpi; /* Y resolution */
- ppd_file_t *ppd; /* PPD file record */
- ppd_attr_t *attr; /* PPD attribute */
- ppd_size_t *size; /* Size record */
- ppd_group_t *group; /* UI group */
- ppd_option_t *option; /* Standard UI option */
- ppd_group_t *group2; /* UI group */
- ppd_option_t *option2; /* Standard UI option */
- ppd_choice_t *choice; /* Standard UI option choice */
+ int i, j, k, m, n; /* Looping vars */
+ int len; /* Length of option name */
+ char *opt; /* Option character */
+ const char *ptr; /* Pointer into string */
+ int files; /* Number of files */
+ int verbose; /* Want verbose output? */
+ int warn; /* Which errors to just warn about */
+ int ignore; /* Which errors to ignore */
+ int status; /* Exit status */
+ int errors; /* Number of conformance errors */
+ int ppdversion; /* PPD spec version in PPD file */
+ ppd_status_t error; /* Status of ppdOpen*() */
+ int line; /* Line number for error */
+ char *root; /* Root directory */
+ int xdpi, /* X resolution */
+ ydpi; /* Y resolution */
+ ppd_file_t *ppd; /* PPD file record */
+ ppd_attr_t *attr; /* PPD attribute */
+ ppd_size_t *size; /* Size record */
+ ppd_group_t *group; /* UI group */
+ ppd_option_t *option; /* Standard UI option */
+ ppd_group_t *group2; /* UI group */
+ ppd_option_t *option2; /* Standard UI option */
+ ppd_choice_t *choice; /* Standard UI option choice */
+ struct lconv *loc; /* Locale data */
static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
static char *sections[] = { "ANY", "DOCUMENT", "EXIT",
"JCL", "PAGE", "PROLOG" };
_cupsSetLocale(argv);
+ loc = localeconv();
/*
* Display PPD files for each file listed on the command-line...
ppd = NULL;
files = 0;
status = ERROR_NONE;
+ root = "";
+ warn = WARN_NONE;
+ ignore = WARN_NONE;
for (i = 1; i < argc; i ++)
if (argv[i][0] == '-' && argv[i][1])
for (opt = argv[i] + 1; *opt; opt ++)
switch (*opt)
{
+ case 'I' : /* Ignore errors */
+ i ++;
+
+ if (i >= argc)
+ usage();
+
+ if (!strcmp(argv[i], "none"))
+ ignore = WARN_NONE;
+ else if (!strcmp(argv[i], "filters"))
+ ignore |= WARN_FILTERS;
+ else if (!strcmp(argv[i], "profiles"))
+ ignore |= WARN_PROFILES;
+ else if (!strcmp(argv[i], "all"))
+ ignore = WARN_FILTERS | WARN_PROFILES;
+ else
+ usage();
+ break;
+
+ case 'R' : /* Alternate root directory */
+ i ++;
+
+ if (i >= argc)
+ usage();
+
+ root = argv[i];
+ break;
+
+ case 'W' : /* Turn errors into warnings */
+ i ++;
+
+ if (i >= argc)
+ usage();
+
+ if (!strcmp(argv[i], "none"))
+ warn = WARN_NONE;
+ else if (!strcmp(argv[i], "constraints"))
+ warn |= WARN_CONSTRAINTS;
+ else if (!strcmp(argv[i], "defaults"))
+ warn |= WARN_DEFAULTS;
+ else if (!strcmp(argv[i], "duplex"))
+ warn |= WARN_DUPLEX;
+ else if (!strcmp(argv[i], "filters"))
+ warn |= WARN_FILTERS;
+ else if (!strcmp(argv[i], "profiles"))
+ warn |= WARN_PROFILES;
+ else if (!strcmp(argv[i], "sizes"))
+ warn |= WARN_SIZES;
+ else if (!strcmp(argv[i], "translations"))
+ warn |= WARN_TRANSLATIONS;
+ else if (!strcmp(argv[i], "all"))
+ warn = WARN_ALL;
+ else
+ usage();
+ break;
+
case 'q' : /* Quiet mode */
if (verbose > 0)
{
* Read from stdin...
*/
- if (verbose >= 0)
- printf("(stdin):");
-
ppd = ppdOpen(stdin);
+
+ if (verbose >= 0)
+ printf("%s:", (ppd && ppd->pcfilename) ? ppd->pcfilename : "(stdin)");
}
else
{
if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
attr->value)
- ppdversion = (int)(10 * atof(attr->value) + 0.5);
+ ppdversion = (int)(10 * _cupsStrScand(attr->value, NULL, loc) + 0.5);
+
+ for (j = 0; j < ppd->num_filters; j ++)
+ if (strstr(ppd->filters[j], "application/vnd.cups-raster"))
+ {
+ if (!test_raster(ppd, verbose))
+ errors ++;
+ break;
+ }
/*
* Look for default keywords with no matching option...
*/
- for (j = 0; j < ppd->num_attrs; j ++)
- {
- attr = ppd->attrs[j];
-
- if (!strcmp(attr->name, "DefaultColorSpace") ||
- !strcmp(attr->name, "DefaultFont") ||
- !strcmp(attr->name, "DefaultImageableArea") ||
- !strcmp(attr->name, "DefaultOutputOrder") ||
- !strcmp(attr->name, "DefaultPaperDimension") ||
- !strcmp(attr->name, "DefaultTransfer"))
- continue;
-
- if (!strncmp(attr->name, "Default", 7))
- {
- if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
- strcmp(attr->value, "Unknown"))
- {
- /*
- * Check that the default option value matches a choice...
- */
-
- for (k = 0; k < option->num_choices; k ++)
- if (!strcmp(option->choices[k].choice, attr->value))
- break;
-
- if (k >= option->num_choices)
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** %s %s does not exist!\n"),
- attr->name, attr->value);
- }
-
- errors ++;
- }
- }
- }
- }
+ if (!(warn & WARN_DEFAULTS))
+ errors = check_defaults(ppd, errors, verbose, 0);
if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
{
_cupsLangPuts(stdout, _(" FAIL\n"));
_cupsLangPuts(stdout,
- _(" **FAIL** REQUIRED DefaultImageableArea\n"
+ _(" **FAIL** REQUIRED DefaultImageableArea\n"
" REF: Page 102, section 5.15.\n"));
- }
+ }
errors ++;
}
else if (ppdPageSize(ppd, attr->value) == NULL &&
- strcmp(attr->value, "Unknown"))
+ strcmp(attr->value, "Unknown"))
{
if (verbose >= 0)
{
_cupsLangPuts(stdout, _(" FAIL\n"));
_cupsLangPrintf(stdout,
- _(" **FAIL** BAD DefaultImageableArea %s!\n"
+ _(" **FAIL** BAD DefaultImageableArea %s\n"
" REF: Page 102, section 5.15.\n"),
attr->value);
- }
+ }
errors ++;
}
_cupsLangPuts(stdout, _(" FAIL\n"));
_cupsLangPuts(stdout,
- _(" **FAIL** REQUIRED DefaultPaperDimension\n"
+ _(" **FAIL** REQUIRED DefaultPaperDimension\n"
" REF: Page 103, section 5.15.\n"));
- }
+ }
errors ++;
}
else if (ppdPageSize(ppd, attr->value) == NULL &&
- strcmp(attr->value, "Unknown"))
+ strcmp(attr->value, "Unknown"))
{
if (verbose >= 0)
{
_cupsLangPuts(stdout, _(" FAIL\n"));
_cupsLangPrintf(stdout,
- _(" **FAIL** BAD DefaultPaperDimension %s!\n"
+ _(" **FAIL** BAD DefaultPaperDimension %s\n"
" REF: Page 103, section 5.15.\n"),
attr->value);
- }
+ }
errors ++;
}
if (option->defchoice[0])
{
- if (ppdFindChoice(option, option->defchoice) == NULL &&
- strcmp(option->defchoice, "Unknown"))
+ if (ppdFindChoice(option, option->defchoice) == NULL &&
+ strcmp(option->defchoice, "Unknown"))
{
if (verbose >= 0)
{
_cupsLangPuts(stdout, _(" FAIL\n"));
_cupsLangPrintf(stdout,
- _(" **FAIL** BAD Default%s %s\n"
+ _(" **FAIL** BAD Default%s %s\n"
" REF: Page 40, section 4.5.\n"),
option->keyword, option->defchoice);
- }
+ }
errors ++;
}
else if (verbose > 0)
_cupsLangPrintf(stdout,
- _(" PASS Default%s\n"),
+ _(" PASS Default%s\n"),
option->keyword);
}
else
_cupsLangPuts(stdout, _(" FAIL\n"));
_cupsLangPrintf(stdout,
- _(" **FAIL** REQUIRED Default%s\n"
- " REF: Page 40, section 4.5.\n"),
- option->keyword);
- }
+ _(" **FAIL** REQUIRED Default%s\n"
+ " REF: Page 40, section 4.5.\n"),
+ option->keyword);
+ }
errors ++;
}
}
- if (ppdFindAttr(ppd, "FileVersion", NULL) != NULL)
+ if ((attr = ppdFindAttr(ppd, "FileVersion", NULL)) != NULL)
{
- if (verbose > 0)
+ for (ptr = attr->value; *ptr; ptr ++)
+ if (!isdigit(*ptr & 255) && *ptr != '.')
+ break;
+
+ if (*ptr)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad FileVersion \"%s\"\n"
+ " REF: Page 56, section 5.3.\n"),
+ attr->value);
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
_cupsLangPuts(stdout, _(" PASS FileVersion\n"));
}
else
errors ++;
}
- if (ppdFindAttr(ppd, "FormatVersion", NULL) != NULL)
+ if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL)
{
- if (verbose > 0)
+ ptr = attr->value;
+ if (*ptr == '4' && ptr[1] == '.')
+ {
+
+ for (ptr += 2; *ptr; ptr ++)
+ if (!isdigit(*ptr & 255))
+ break;
+ }
+
+ if (*ptr)
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad FormatVersion \"%s\"\n"
+ " REF: Page 56, section 5.3.\n"),
+ attr->value);
+ }
+
+ errors ++;
+ }
+ else if (verbose > 0)
_cupsLangPuts(stdout, _(" PASS FormatVersion\n"));
}
else
errors ++;
}
+ else if (!strncasecmp(ppd->manufacturer, "OkiData", 7) ||
+ !strncasecmp(ppd->manufacturer, "Oki Data", 8))
+ {
+ if (verbose >= 0)
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPuts(stdout,
+ _(" **FAIL** BAD Manufacturer (should be "
+ "\"Oki\")\n"
+ " REF: Page 211, table D.1.\n"));
+ }
+
+ errors ++;
+ }
else if (verbose > 0)
_cupsLangPuts(stdout, _(" PASS Manufacturer\n"));
}
else
ydpi = xdpi;
- if (xdpi <= 0 || ydpi <= 0 || strcmp(ptr, "dpi"))
+ if (xdpi <= 0 || xdpi > 99999 || ydpi <= 0 || ydpi > 99999 ||
+ strcmp(ptr, "dpi"))
{
if (verbose >= 0)
{
_cupsLangPuts(stdout, _(" FAIL\n"));
_cupsLangPrintf(stdout,
- _(" **FAIL** Bad %s choice %s!\n"
+ _(" **FAIL** Bad %s choice %s\n"
" REF: Page 84, section 5.9\n"),
option->keyword, choice->choice);
}
}
}
- /*
- * Check for a duplex option, and for standard values...
- */
-
- if ((option = ppdFindOption(ppd, "Duplex")) == NULL)
- if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
- if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
- option = ppdFindOption(ppd, "KD03Duplex");
-
- if (option != NULL)
+ if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
+ strcmp(attr->name, "1284DeviceID"))
{
- if (ppdFindChoice(option, "None") == NULL)
+ if (verbose >= 0)
{
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- _cupsLangPrintf(stdout,
- _(" **FAIL** REQUIRED %s does not define "
- "choice None!\n"
- " REF: Page 122, section 5.17\n"),
- option->keyword);
- }
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** %s must be 1284DeviceID\n"
+ " REF: Page 72, section 5.5\n"),
+ attr->name);
+ }
- errors ++;
- }
+ errors ++;
+ }
- for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
- if (strcmp(choice->choice, "None") &&
- strcmp(choice->choice, "DuplexNoTumble") &&
- strcmp(choice->choice, "DuplexTumble") &&
- strcmp(choice->choice, "SimplexTumble"))
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ errors = check_case(ppd, errors, verbose);
- _cupsLangPrintf(stdout,
- _(" **FAIL** Bad %s choice %s!\n"
- " REF: Page 122, section 5.17\n"),
- option->keyword, choice->choice);
- }
+ if (!(warn & WARN_CONSTRAINTS))
+ errors = check_constraints(ppd, errors, verbose, 0);
- errors ++;
- }
- }
+ if (!(warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
+ errors = check_filters(ppd, root, errors, verbose, 0);
+
+ if (!(warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
+ errors = check_profiles(ppd, root, errors, verbose, 0);
+
+ if (!(warn & WARN_SIZES))
+ errors = check_sizes(ppd, errors, verbose, 0);
+
+ if (!(warn & WARN_TRANSLATIONS))
+ errors = check_translations(ppd, errors, verbose, 0);
+
+ if (!(warn & WARN_DUPLEX))
+ errors = check_duplex(ppd, errors, verbose, 0);
if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
- attr->value)
+ attr->value)
{
/*
- * This file contains localizations, check them...
+ * This file contains localizations, check for conformance of the
+ * base translation...
*/
- char *languages, /* Copy of attribute value */
- *langstart, /* Start of current language */
- *langptr, /* Pointer into languages */
- keyword[PPD_MAX_NAME],
- /* Localization keyword */
- ckeyword[PPD_MAX_NAME];
- /* Custom option keyword */
- ppd_coption_t *coption; /* Custom option */
- ppd_cparam_t *cparam; /* Custom parameter */
- cups_array_t *langlist; /* List of languages so far */
- char ll[3]; /* Base language */
-
-
- languages = strdup(attr->value);
- langlist = cupsArrayNew((cups_array_func_t)strcmp, NULL);
-
- for (langptr = languages; *langptr;)
+ if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL)
{
- /*
- * Skip leading whitespace...
- */
-
- while (isspace(*langptr & 255))
- langptr ++;
-
- if (!*langptr)
- break;
-
- /*
- * Find the end of this language name...
- */
+ if (!attr->value || strcmp(attr->value, "ISOLatin1"))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- for (langstart = langptr;
- *langptr && !isspace(*langptr & 255);
- langptr ++);
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Bad LanguageEncoding %s - "
+ "must be ISOLatin1\n"),
+ attr->value ? attr->value : "(null)");
- if (*langptr)
- *langptr++ = '\0';
+ errors ++;
+ }
- j = strlen(langstart);
- if (j != 2 && j != 5)
+ if (!ppd->lang_version || strcmp(ppd->lang_version, "English"))
{
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+ if (verbose >= 0)
_cupsLangPrintf(stdout,
- _(" **FAIL** Bad language \"%s\"!\n"),
- langstart);
- }
+ _(" **FAIL** Bad LanguageVersion %s - "
+ "must be English\n"),
+ ppd->lang_version ? ppd->lang_version : "(null)");
- errors ++;
- continue;
+ errors ++;
}
-
- cupsArrayAdd(langlist, langstart);
-
- /*
+
+ /*
* Loop through all options and choices...
*/
- for (option = ppdFirstOption(ppd);
+ for (option = ppdFirstOption(ppd);
option;
option = ppdNextOption(ppd))
{
- snprintf(keyword, sizeof(keyword), "%s.Translation", langstart);
- if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL)
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ /*
+ * Check for special characters outside A0 to BF, F7, or F8
+ * that are used for languages other than English.
+ */
- _cupsLangPrintf(stdout,
- _(" **FAIL** Missing \"%s\" translation "
- "string for option %s!\n"),
- langstart, option->keyword);
- }
+ for (ptr = option->text; *ptr; ptr ++)
+ if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
+ (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
+ break;
- errors ++;
- }
- else if (!valid_utf8(attr->text))
+ if (*ptr)
{
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Bad UTF-8 \"%s\" translation "
- "string for option %s!\n"),
- langstart, option->keyword);
- }
-
- errors ++;
- }
-
- for (ptr = option->text; *ptr; ptr ++)
- if (*ptr & 128)
- break;
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- if (*ptr)
- {
if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
_cupsLangPrintf(stdout,
- _(" **FAIL** Default translation "
+ _(" **FAIL** Default translation "
"string for option %s contains 8-bit "
- "characters!\n"),
+ "characters\n"),
option->keyword);
- }
errors ++;
}
- snprintf(keyword, sizeof(keyword), "%s.%s", langstart,
- option->keyword);
- for (j = 0; j < option->num_choices; j ++)
+ for (j = 0; j < option->num_choices; j ++)
{
- if (!strcasecmp(option->choices[j].choice, "Custom") &&
- (coption = ppdFindCustomOption(ppd,
- option->keyword)) != NULL)
- {
- snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
- langstart, option->keyword);
-
- if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
- !valid_utf8(attr->text))
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Bad UTF-8 \"%s\" "
- "translation string for option %s, "
- "choice %s!\n"),
- langstart, ckeyword + 1 + strlen(langstart),
- "True");
- }
+ /*
+ * Check for special characters outside A0 to BF, F7, or F8
+ * that are used for languages other than English.
+ */
- errors ++;
- }
+ for (ptr = option->choices[j].text; *ptr; ptr ++)
+ if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
+ (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
+ break;
- if (strcasecmp(option->keyword, "PageSize"))
- {
- for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
- cparam;
- cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
- {
- snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
- langstart, option->keyword);
- if ((attr = ppdFindAttr(ppd, ckeyword, cparam->name)) == NULL)
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Missing \"%s\" "
- "translation string for option %s, "
- "choice %s!\n"),
- langstart,
- ckeyword + 1 + strlen(langstart),
- cparam->name);
- }
-
- errors ++;
- }
- else if (!valid_utf8(attr->text))
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Bad UTF-8 \"%s\" "
- "translation string for option %s, "
- "choice %s!\n"),
- langstart,
- ckeyword + 1 + strlen(langstart),
- cparam->name);
- }
-
- errors ++;
- }
- }
- }
- }
- else if ((attr = ppdFindAttr(ppd, keyword, option->choices[j].choice)) == NULL)
+ if (*ptr)
{
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Missing \"%s\" "
- "translation string for option %s, "
- "choice %s!\n"),
- langstart, option->keyword,
- option->choices[j].choice);
- }
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- errors ++;
- }
- else if (!valid_utf8(attr->text))
- {
if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
_cupsLangPrintf(stdout,
- _(" **FAIL** Bad UTF-8 \"%s\" "
- "translation string for option %s, "
- "choice %s!\n"),
- langstart, option->keyword,
+ _(" **FAIL** Default translation "
+ "string for option %s choice %s contains "
+ "8-bit characters\n"),
+ option->keyword,
option->choices[j].choice);
- }
errors ++;
}
+ }
+ }
+ }
+ }
- for (ptr = option->choices[j].text; *ptr; ptr ++)
- if (*ptr & 128)
- break;
-
- if (*ptr)
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Default translation "
- "string for option %s choice %s contains "
- "8-bit characters!\n"),
- option->keyword,
- option->choices[j].choice);
- }
+ /*
+ * Final pass/fail notification...
+ */
- errors ++;
- }
- }
- }
- }
+ if (errors)
+ status = ERROR_CONFORMANCE;
+ else if (!verbose)
+ _cupsLangPuts(stdout, _(" PASS\n"));
- /*
- * Verify that we have the base language for each localized one...
- */
+ if (verbose >= 0)
+ {
+ check_basics(argv[i]);
- for (langptr = (char *)cupsArrayFirst(langlist);
- langptr;
- langptr = (char *)cupsArrayNext(langlist))
- if (langptr[2])
- {
- /*
- * Lookup the base language...
- */
+ if (warn & WARN_DEFAULTS)
+ errors = check_defaults(ppd, errors, verbose, 1);
- cupsArraySave(langlist);
+ if (warn & WARN_CONSTRAINTS)
+ errors = check_constraints(ppd, errors, verbose, 1);
- strlcpy(ll, langptr, sizeof(ll));
+ if ((warn & WARN_FILTERS) && !(ignore & WARN_FILTERS))
+ errors = check_filters(ppd, root, errors, verbose, 1);
- if (!cupsArrayFind(langlist, ll))
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ if ((warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
+ errors = check_profiles(ppd, root, errors, verbose, 1);
- _cupsLangPrintf(stdout,
- _(" **FAIL** No base translation \"%s\" "
- "is included in file!\n"), ll);
- }
+ if (warn & WARN_SIZES)
+ errors = check_sizes(ppd, errors, verbose, 1);
+ else
+ errors = check_sizes(ppd, errors, verbose, 2);
- errors ++;
- }
+ if (warn & WARN_TRANSLATIONS)
+ errors = check_translations(ppd, errors, verbose, 1);
- cupsArrayRestore(langlist);
- }
+ if (warn & WARN_DUPLEX)
+ errors = check_duplex(ppd, errors, verbose, 1);
/*
- * Free memory used for the languages...
+ * Look for legacy duplex keywords...
*/
- cupsArrayDelete(langlist);
- free(languages);
- }
-
- for (attr = ppdFindAttr(ppd, "cupsFilter", NULL);
- attr;
- attr = ppdFindNextAttr(ppd, "cupsFilter", NULL))
- {
- char super[16], /* Filter super type */
- type[256], /* Filter type */
- program[256]; /* Filter program */
- int cost; /* Filter cost */
-
-
- if (!attr->value ||
- sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
- program) != 4)
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
-
- _cupsLangPrintf(stdout,
- _(" **FAIL** Bad cupsFilter value \"%s\"!\n"),
- attr->value ? attr->value : "");
- }
-
- errors ++;
- }
- }
-
- if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
- strcmp(attr->name, "1284DeviceID"))
- {
- if (verbose >= 0)
- {
- if (!errors && !verbose)
- _cupsLangPuts(stdout, _(" FAIL\n"));
+ if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
+ if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
+ option = ppdFindOption(ppd, "KD03Duplex");
+ if (option)
_cupsLangPrintf(stdout,
- _(" **FAIL** %s must be 1284DeviceID!\n"
- " REF: Page 72, section 5.5\n"),
- attr->name);
- }
-
- errors ++;
- }
-
- if (errors)
- status = ERROR_CONFORMANCE;
- else if (!verbose)
- _cupsLangPuts(stdout, _(" PASS\n"));
-
- if (verbose >= 0)
- {
- check_basics(argv[i]);
+ _(" WARN Duplex option keyword %s may not "
+ "work as expected and should be named Duplex\n"
+ " REF: Page 122, section 5.17\n"),
+ option->keyword);
/*
* Look for default keywords with no corresponding option...
if (!strcmp(attr->name, "DefaultColorSpace") ||
!strcmp(attr->name, "DefaultColorSep") ||
!strcmp(attr->name, "DefaultFont") ||
+ !strcmp(attr->name, "DefaultHalftoneType") ||
!strcmp(attr->name, "DefaultImageableArea") ||
+ !strcmp(attr->name, "DefaultLeadingEdge") ||
!strcmp(attr->name, "DefaultOutputOrder") ||
!strcmp(attr->name, "DefaultPaperDimension") ||
+ !strcmp(attr->name, "DefaultResolution") ||
!strcmp(attr->name, "DefaultScreenProc") ||
!strcmp(attr->name, "DefaultTransfer"))
continue;
!ppdFindOption(ppd, attr->name + 7))
_cupsLangPrintf(stdout,
_(" WARN %s has no corresponding "
- "options!\n"),
+ "options\n"),
attr->name);
}
- /*
- * Check for old Duplex option names...
- */
-
- if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
- option = ppdFindOption(ppd, "KD03Duplex");
-
- if (option)
- {
- _cupsLangPrintf(stdout,
- _(" WARN Duplex option keyword %s "
- "should be named Duplex or JCLDuplex!\n"
- " REF: Page 122, section 5.17\n"),
- option->keyword);
- }
-
ppdMarkDefaults(ppd);
if (ppdConflicts(ppd))
{
_cupsLangPuts(stdout,
- _(" WARN Default choices conflicting!\n"));
+ _(" WARN Default choices conflicting\n"));
show_conflicts(ppd);
}
if (ppdversion < 43)
{
_cupsLangPrintf(stdout,
- _(" WARN Obsolete PPD version %.1f!\n"
+ _(" WARN Obsolete PPD version %.1f\n"
" REF: Page 42, section 5.2.\n"),
0.1f * ppdversion);
}
for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++)
for (k = 0, option = group->options; k < group->num_options; k ++, option ++)
{
- len = strlen(option->keyword);
+ len = (int)strlen(option->keyword);
for (m = 0, group2 = ppd->groups;
m < ppd->num_groups;
n < group2->num_options;
n ++, option2 ++)
if (option != option2 &&
- len < strlen(option2->keyword) &&
+ len < (int)strlen(option2->keyword) &&
!strncmp(option->keyword, option2->keyword, len))
{
_cupsLangPrintf(stdout,
}
}
+ _cupsLangPrintf(stdout, " num_consts = %d\n",
+ ppd->num_consts);
+ for (j = 0; j < ppd->num_consts; j ++)
+ _cupsLangPrintf(stdout,
+ " consts[%d] = *%s %s *%s %s\n",
+ j, ppd->consts[j].option1, ppd->consts[j].choice1,
+ ppd->consts[j].option2, ppd->consts[j].choice2);
+
_cupsLangPrintf(stdout, " num_profiles = %d\n",
ppd->num_profiles);
for (j = 0; j < ppd->num_profiles; j ++)
* 'check_basics()' - Check for CR LF, mixed line endings, and blank lines.
*/
-void
+static void
check_basics(const char *filename) /* I - PPD file to check */
{
cups_file_t *fp; /* File pointer */
if (eol == EOL_NONE)
eol = EOL_CRLF;
- else
+ else if (eol != EOL_CRLF)
mixed = 1;
}
else if (eol == EOL_NONE)
eol = EOL_CR;
- else
+ else if (eol != EOL_CR)
mixed = 1;
}
if (col > 0 && whitespace)
_cupsLangPrintf(stdout,
- _(" WARN Line %d only contains whitespace!\n"),
+ _(" WARN Line %d only contains whitespace\n"),
linenum);
linenum ++;
if (mixed)
_cupsLangPuts(stdout,
_(" WARN File contains a mix of CR, LF, and "
- "CR LF line endings!\n"));
+ "CR LF line endings\n"));
if (eol == EOL_CRLF)
_cupsLangPuts(stdout,
_(" WARN Non-Windows PPD files should use lines "
- "ending with only LF, not CR LF!\n"));
+ "ending with only LF, not CR LF\n"));
cupsFileClose(fp);
}
/*
- * 'show_conflicts()' - Show option conflicts in a PPD file.
+ * 'check_constraints()' - Check UIConstraints in the PPD file.
*/
-void
-show_conflicts(ppd_file_t *ppd) /* I - PPD to check */
+static int /* O - Errors found */
+check_constraints(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
{
- int i, j; /* Looping variables */
- ppd_const_t *c; /* Current constraint */
- ppd_option_t *o1, *o2; /* Options */
- ppd_choice_t *c1, *c2; /* Choices */
+ int i; /* Looping var */
+ const char *prefix; /* WARN/FAIL prefix */
+ ppd_const_t *c; /* Current UIConstraints data */
+ ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
+ const char *vptr; /* Pointer into constraint value */
+ char option[PPD_MAX_NAME],
+ /* Option name/MainKeyword */
+ choice[PPD_MAX_NAME],
+ /* Choice/OptionKeyword */
+ *ptr; /* Pointer into option or choice */
+ int num_options; /* Number of options */
+ cups_option_t *options; /* Options */
+ ppd_option_t *o; /* PPD option */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
/*
- * Loop through all of the UI constraints and report any options
- * that conflict...
+ * See what kind of constraint data we have in the PPD...
*/
- for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL)
{
/*
- * Grab pointers to the first option...
+ * Check new-style cupsUIConstraints data...
*/
- o1 = ppdFindOption(ppd, c->option1);
-
- if (o1 == NULL)
- continue;
- else if (c->choice1[0] != '\0')
+ for (; constattr;
+ constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
{
- /*
- * This constraint maps to a specific choice.
- */
+ if (!constattr->value)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- c1 = ppdFindChoice(o1, c->choice1);
- }
- else
- {
- /*
- * This constraint applies to any choice for this option.
- */
+ _cupsLangPrintf(stdout,
+ _(" %s Empty cupsUIConstraints %s\n"),
+ prefix, constattr->spec);
- for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
- if (c1->marked)
- break;
+ if (!warn)
+ errors ++;
- if (j == 0 ||
- !strcasecmp(c1->choice, "None") ||
- !strcasecmp(c1->choice, "Off") ||
- !strcasecmp(c1->choice, "False"))
- c1 = NULL;
- }
+ continue;
+ }
- /*
- * Grab pointers to the second option...
- */
+ for (i = 0, vptr = strchr(constattr->value, '*');
+ vptr;
+ i ++, vptr = strchr(vptr + 1, '*'));
- o2 = ppdFindOption(ppd, c->option2);
+ if (i == 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsUIConstraints %s: \"%s\"\n"),
+ prefix, constattr->spec, constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ cupsArraySave(ppd->sorted_attrs);
+
+ if (constattr->spec[0] &&
+ !ppdFindAttr(ppd, "cupsUIResolver", constattr->spec))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing cupsUIResolver %s\n"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
+ cupsArrayRestore(ppd->sorted_attrs);
+
+ num_options = 0;
+ options = NULL;
+
+ for (vptr = strchr(constattr->value, '*');
+ vptr;
+ vptr = strchr(vptr, '*'))
+ {
+ /*
+ * Extract "*Option Choice" or just "*Option"...
+ */
+
+ for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
+ if (ptr < (option + sizeof(option) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+
+ while (isspace(*vptr & 255))
+ vptr ++;
+
+ if (*vptr == '*')
+ choice[0] = '\0';
+ else
+ {
+ for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
+ if (ptr < (choice + sizeof(choice) - 1))
+ *ptr++ = *vptr;
+
+ *ptr = '\0';
+ }
+
+ if (!strncasecmp(option, "Custom", 6) && !strcasecmp(choice, "True"))
+ {
+ _cups_strcpy(option, option + 6);
+ strcpy(choice, "Custom");
+ }
+
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "cupsUIConstraints %s: \"%s\"\n"),
+ prefix, option, constattr->spec, constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "cupsUIConstraints %s: \"%s\"\n"),
+ prefix, option, choice, constattr->spec,
+ constattr->value);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (choice[0])
+ num_options = cupsAddOption(option, choice, num_options, &options);
+ else
+ {
+ for (i = 0; i < o->num_choices; i ++)
+ if (strcasecmp(o->choices[i].choice, "None") &&
+ strcasecmp(o->choices[i].choice, "Off") &&
+ strcasecmp(o->choices[i].choice, "False"))
+ {
+ num_options = cupsAddOption(option, o->choices[i].choice,
+ num_options, &options);
+ break;
+ }
+ }
+ }
- if (o2 == NULL)
- continue;
- else if (c->choice2[0] != '\0')
- {
/*
- * This constraint maps to a specific choice.
+ * Resolvers must list at least two options...
*/
- c2 = ppdFindChoice(o2, c->choice2);
- }
- else
- {
+ if (num_options < 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s cupsUIResolver %s does not list at least "
+ "two different options\n"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
/*
- * This constraint applies to any choice for this option.
+ * Test the resolver...
*/
- for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
- if (c2->marked)
- break;
+ if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
- if (j == 0 ||
- !strcasecmp(c2->choice, "None") ||
- !strcasecmp(c2->choice, "Off") ||
- !strcasecmp(c2->choice, "False"))
- c2 = NULL;
- }
+ _cupsLangPrintf(stdout,
+ _(" %s cupsUIResolver %s causes a loop\n"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+ cupsFreeOptions(num_options, options);
+ }
+ }
+ else
+ {
/*
- * If both options are marked then there is a conflict...
+ * Check old-style [Non]UIConstraints data...
*/
- if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
- _cupsLangPrintf(stdout,
- _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
- " (constraint=\"%s %s %s %s\")\n"),
- o1->keyword, c1->choice, o2->keyword, c2->choice,
- c->option1, c->choice1, c->option2, c->choice2);
- }
-}
+ for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ {
+ if (!strncasecmp(c->option1, "Custom", 6) &&
+ !strcasecmp(c->choice1, "True"))
+ {
+ strcpy(option, c->option1 + 6);
+ strcpy(choice, "Custom");
+ }
+ else
+ {
+ strcpy(option, c->option1);
+ strcpy(choice, c->choice1);
+ }
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
-/*
- * 'usage()' - Show program usage...
- */
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "UIConstraints \"*%s %s *%s %s\"\n"),
+ prefix, c->option1,
+ c->option1, c->choice1, c->option2, c->choice2);
-void
-usage(void)
-{
- _cupsLangPuts(stdout,
- _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] "
- "[... filenameN.ppd[.gz]]\n"
- " program | cupstestppd [-q] [-r] [-v[v]] -\n"));
+ if (!warn)
+ errors ++;
+ }
+ else if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "UIConstraints \"*%s %s *%s %s\"\n"),
+ prefix, c->option1, c->choice1,
+ c->option1, c->choice1, c->option2, c->choice2);
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (!strncasecmp(c->option2, "Custom", 6) &&
+ !strcasecmp(c->choice2, "True"))
+ {
+ strcpy(option, c->option2 + 6);
+ strcpy(choice, "Custom");
+ }
+ else
+ {
+ strcpy(option, c->option2);
+ strcpy(choice, c->choice2);
+ }
+
+ if ((o = ppdFindOption(ppd, option)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing option %s in "
+ "UIConstraints \"*%s %s *%s %s\"\n"),
+ prefix, c->option2,
+ c->option1, c->choice1, c->option2, c->choice2);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (choice[0] && !ppdFindChoice(o, choice))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Missing choice *%s %s in "
+ "UIConstraints \"*%s %s *%s %s\"\n"),
+ prefix, c->option2, c->choice2,
+ c->option1, c->choice1, c->option2, c->choice2);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_case()' - Check that there are no duplicate groups, options,
+ * or choices that differ only by case.
+ */
+
+static int /* O - Errors found */
+check_case(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose) /* I - Verbosity level */
+{
+ int i, j; /* Looping vars */
+ ppd_group_t *groupa, /* First group */
+ *groupb; /* Second group */
+ ppd_option_t *optiona, /* First option */
+ *optionb; /* Second option */
+ ppd_choice_t *choicea, /* First choice */
+ *choiceb; /* Second choice */
+
+
+ /*
+ * Check that the groups do not have any duplicate names...
+ */
+
+ for (i = ppd->num_groups, groupa = ppd->groups; i > 1; i --, groupa ++)
+ for (j = i - 1, groupb = groupa + 1; j > 0; j --, groupb ++)
+ if (!strcasecmp(groupa->name, groupb->name))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Group names %s and %s differ only "
+ "by case\n"),
+ groupa->name, groupb->name);
+
+ errors ++;
+ }
+
+ /*
+ * Check that the options do not have any duplicate names...
+ */
+
+ for (optiona = ppdFirstOption(ppd); optiona; optiona = ppdNextOption(ppd))
+ {
+ cupsArraySave(ppd->options);
+ for (optionb = ppdNextOption(ppd); optionb; optionb = ppdNextOption(ppd))
+ if (!strcasecmp(optiona->keyword, optionb->keyword))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Option names %s and %s differ only "
+ "by case\n"),
+ optiona->keyword, optionb->keyword);
+
+ errors ++;
+ }
+ cupsArrayRestore(ppd->options);
+
+ /*
+ * Then the choices...
+ */
+
+ for (i = optiona->num_choices, choicea = optiona->choices;
+ i > 1;
+ i --, choicea ++)
+ for (j = i - 1, choiceb = choicea + 1; j > 0; j --, choiceb ++)
+ if (!strcmp(choicea->choice, choiceb->choice))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Multiple occurrences of %s "
+ "choice name %s\n"),
+ optiona->keyword, choicea->choice);
+
+ errors ++;
+
+ choicea ++;
+ i --;
+ break;
+ }
+ else if (!strcasecmp(choicea->choice, choiceb->choice))
+ {
+ if (!errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** %s choice names %s and %s "
+ "differ only by case\n"),
+ optiona->keyword, choicea->choice, choiceb->choice);
+
+ errors ++;
+ }
+ }
+
+ /*
+ * Return the number of errors found...
+ */
+
+ return (errors);
+}
+
+
+/*
+ * 'check_defaults()' - Check default option keywords in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_defaults(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int j, k; /* Looping vars */
+ ppd_attr_t *attr; /* PPD attribute */
+ ppd_option_t *option; /* Standard UI option */
+ const char *prefix; /* WARN/FAIL prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ for (j = 0; j < ppd->num_attrs; j ++)
+ {
+ attr = ppd->attrs[j];
+
+ if (!strcmp(attr->name, "DefaultColorSpace") ||
+ !strcmp(attr->name, "DefaultFont") ||
+ !strcmp(attr->name, "DefaultHalftoneType") ||
+ !strcmp(attr->name, "DefaultImageableArea") ||
+ !strcmp(attr->name, "DefaultLeadingEdge") ||
+ !strcmp(attr->name, "DefaultOutputOrder") ||
+ !strcmp(attr->name, "DefaultPaperDimension") ||
+ !strcmp(attr->name, "DefaultResolution") ||
+ !strcmp(attr->name, "DefaultTransfer"))
+ continue;
+
+ if (!strncmp(attr->name, "Default", 7))
+ {
+ if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
+ strcmp(attr->value, "Unknown"))
+ {
+ /*
+ * Check that the default option value matches a choice...
+ */
+
+ for (k = 0; k < option->num_choices; k ++)
+ if (!strcmp(option->choices[k].choice, attr->value))
+ break;
+
+ if (k >= option->num_choices)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s %s %s does not exist\n"),
+ prefix, attr->name, attr->value);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_duplex()' - Check duplex keywords in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_duplex(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Error found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_option_t *option; /* PPD option */
+ ppd_choice_t *choice; /* Current choice */
+ const char *prefix; /* Message prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * Check for a duplex option, and for standard values...
+ */
+
+ if ((option = ppdFindOption(ppd, "Duplex")) != NULL)
+ {
+ if (!ppdFindChoice(option, "None"))
+ {
+ if (verbose >= 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s REQUIRED %s does not define "
+ "choice None\n"
+ " REF: Page 122, section 5.17\n"),
+ prefix, option->keyword);
+ }
+
+ if (!warn)
+ errors ++;
+ }
+
+ for (i = option->num_choices, choice = option->choices;
+ i > 0;
+ i --, choice ++)
+ if (strcmp(choice->choice, "None") &&
+ strcmp(choice->choice, "DuplexNoTumble") &&
+ strcmp(choice->choice, "DuplexTumble") &&
+ strcmp(choice->choice, "SimplexTumble"))
+ {
+ if (verbose >= 0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s Bad %s choice %s\n"
+ " REF: Page 122, section 5.17\n"),
+ prefix, option->keyword, choice->choice);
+ }
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_filters()' - Check filters in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_filters(ppd_file_t *ppd, /* I - PPD file */
+ const char *root, /* I - Root directory */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_attr_t *attr; /* PPD attribute */
+ const char *ptr; /* Pointer into string */
+ char super[16], /* Super-type for filter */
+ type[256], /* Type for filter */
+ program[1024], /* Program/filter name */
+ pathprog[1024]; /* Complete path to program/filter */
+ int cost; /* Cost of filter */
+ const char *prefix; /* WARN/FAIL prefix */
+ struct stat fileinfo; /* File information */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * cupsFilter
+ */
+
+ for (i = 0; i < ppd->num_filters; i ++)
+ {
+ if (sscanf(ppd->filters[i], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
+ &cost, program) != 4)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsFilter value \"%s\"\n"),
+ prefix, ppd->filters[i]);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (strcmp(program, "-"))
+ {
+ if (program[0] == '/')
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
+ else
+ {
+ if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
+ ptr = CUPS_SERVERBIN;
+
+ if (*ptr == '/' || !*root)
+ snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
+ program);
+ else
+ snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
+ program);
+ }
+
+ if (stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing cupsFilter "
+ "file \"%s\"\n"), prefix, pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on cupsFilter "
+ "file \"%s\"\n"), prefix, pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("cupsFilter", pathprog, errors, verbose, warn);
+ }
+ }
+
+ /*
+ * cupsPreFilter
+ */
+
+ for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
+ {
+ if (strcmp(attr->name, "cupsPreFilter"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s\n"),
+ prefix, attr->name, "cupsPreFilter");
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (!attr->value ||
+ sscanf(attr->value, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
+ &cost, program) != 4)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsPreFilter value \"%s\"\n"),
+ prefix, attr->value ? attr->value : "");
+
+ if (!warn)
+ errors ++;
+ }
+ else if (strcmp(program, "-"))
+ {
+ if (program[0] == '/')
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
+ else
+ {
+ if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
+ ptr = CUPS_SERVERBIN;
+
+ if (*ptr == '/' || !*root)
+ snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
+ program);
+ else
+ snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
+ program);
+ }
+
+ if (stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing cupsPreFilter "
+ "file \"%s\"\n"), prefix, pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_PROGRAM)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on "
+ "cupsPreFilter file \"%s\"\n"), prefix,
+ pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("cupsPreFilter", pathprog, errors, verbose, warn);
+ }
+ }
+
+#ifdef __APPLE__
+ /*
+ * APDialogExtension
+ */
+
+ for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL);
+ attr != NULL;
+ attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
+ {
+ if (strcmp(attr->name, "APDialogExtension"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s\n"),
+ prefix, attr->name, "APDialogExtension");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APDialogExtension file \"%s\"\n"),
+ prefix, pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on "
+ "APDialogExtension file \"%s\"\n"), prefix,
+ pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APDialogExtension", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterIconPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APPrinterIconPath"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s\n"),
+ prefix, attr->name, "APPrinterIconPath");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APPrinterIconPath file \"%s\"\n"),
+ prefix, pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on "
+ "APPrinterIconPath file \"%s\"\n"), prefix,
+ pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterIconPath", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterLowInkTool
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterLowInkTool", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APPrinterLowInkTool"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s\n"),
+ prefix, attr->name, "APPrinterLowInkTool");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APPrinterLowInkTool file \"%s\"\n"),
+ prefix, pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on "
+ "APPrinterLowInkTool file \"%s\"\n"), prefix,
+ pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterLowInkTool", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterUtilityPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterUtilityPath", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APPrinterUtilityPath"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s\n"),
+ prefix, attr->name, "APPrinterUtilityPath");
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(pathprog, sizeof(pathprog), "%s%s", root,
+ attr->value ? attr->value : "(null)");
+
+ if (!attr->value || stat(pathprog, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APPrinterUtilityPath file \"%s\"\n"),
+ prefix, pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on "
+ "APPrinterUtilityPath file \"%s\"\n"), prefix,
+ pathprog);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterUtilityPath", pathprog, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APScanAppBundleID and APScanAppPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APScanAppPath", NULL)) != NULL)
+ {
+ if (strcmp(attr->name, "APScanAppPath"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad spelling of %s - should be %s\n"),
+ prefix, attr->name, "APScanAppPath");
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (!attr->value || stat(attr->value, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APScanAppPath file \"%s\"\n"),
+ prefix, attr->value ? attr->value : "<NULL>");
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on "
+ "APScanAppPath file \"%s\"\n"), prefix,
+ attr->value);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APScanAppPath", attr->value, errors, verbose,
+ warn);
+
+ if (ppdFindAttr(ppd, "APScanAppBundleID", NULL))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Cannot provide both "
+ "APScanAppPath and APScanAppBundleID\n"),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+#endif /* __APPLE__ */
+
+ return (errors);
+}
+
+
+/*
+ * 'check_profiles()' - Check ICC color profiles in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_profiles(ppd_file_t *ppd, /* I - PPD file */
+ const char *root, /* I - Root directory */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping var */
+ ppd_attr_t *attr; /* PPD attribute */
+ const char *ptr; /* Pointer into string */
+ const char *prefix; /* WARN/FAIL prefix */
+ char filename[1024]; /* Profile filename */
+ struct stat fileinfo; /* File information */
+ int num_profiles = 0; /* Number of profiles */
+ unsigned hash, /* Current hash value */
+ hashes[1000]; /* Hash values of profile names */
+ const char *specs[1000]; /* Specifiers for profiles */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
+ attr;
+ attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
+ {
+ /*
+ * Check for valid selector...
+ */
+
+ for (i = 0, ptr = strchr(attr->spec, '.'); ptr; ptr = strchr(ptr + 1, '.'))
+ i ++;
+
+ if (!attr->value || i < 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad cupsICCProfile %s\n"),
+ prefix, attr->spec);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ /*
+ * Check for valid profile filename...
+ */
+
+ if (attr->value[0] == '/')
+ snprintf(filename, sizeof(filename), "%s%s", root, attr->value);
+ else
+ {
+ if ((ptr = getenv("CUPS_DATADIR")) == NULL)
+ ptr = CUPS_DATADIR;
+
+ if (*ptr == '/' || !*root)
+ snprintf(filename, sizeof(filename), "%s%s/profiles/%s", root, ptr,
+ attr->value);
+ else
+ snprintf(filename, sizeof(filename), "%s/%s/profiles/%s", root, ptr,
+ attr->value);
+ }
+
+ if (stat(filename, &fileinfo))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing cupsICCProfile "
+ "file \"%s\"\n"), prefix, filename);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (fileinfo.st_uid != 0 ||
+ (fileinfo.st_mode & MODE_WRITE) ||
+ (fileinfo.st_mode & MODE_MASK) != MODE_DATAFILE)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Bad permissions on "
+ "cupsICCProfile file \"%s\"\n"), prefix,
+ filename);
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("cupsICCProfile", filename, errors, verbose, warn);
+
+ /*
+ * Check for hash collisions...
+ */
+
+ hash = _ppdHashName(attr->spec);
+
+ if (num_profiles > 0)
+ {
+ for (i = 0; i < num_profiles; i ++)
+ if (hashes[i] == hash)
+ break;
+
+ if (i < num_profiles)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s cupsICCProfile %s hash value "
+ "collides with %s\n"), prefix, attr->spec,
+ specs[i]);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ /*
+ * Remember up to 1000 profiles...
+ */
+
+ if (num_profiles < 1000)
+ {
+ hashes[num_profiles] = hash;
+ specs[num_profiles] = attr->spec;
+ num_profiles ++;
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_sizes()' - Check media sizes in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_sizes(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping vars */
+ ppd_size_t *size; /* Current size */
+ int width, /* Custom width */
+ length; /* Custom length */
+ char name[PPD_MAX_NAME], /* Size name without dot suffix */
+ *nameptr; /* Pointer into name */
+ const char *prefix; /* WARN/FAIL prefix */
+ ppd_option_t *page_size, /* PageSize option */
+ *page_region; /* PageRegion option */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ if ((page_size = ppdFindOption(ppd, "PageSize")) == NULL && warn != 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing REQUIRED PageSize option\n"
+ " REF: Page 99, section 5.14.\n"),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+
+ if ((page_region = ppdFindOption(ppd, "PageRegion")) == NULL && warn != 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing REQUIRED PageRegion option\n"
+ " REF: Page 100, section 5.14.\n"),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ {
+ /*
+ * Check that the size name is standard...
+ */
+
+ if (!strcmp(size->name, "Custom"))
+ {
+ /*
+ * Skip custom page size...
+ */
+
+ continue;
+ }
+ else if (warn != 2 && size->name[0] == 'w' &&
+ sscanf(size->name, "w%dh%d", &width, &length) == 2)
+ {
+ /*
+ * Validate device-specific size wNNNhNNN should have proper width and
+ * length...
+ */
+
+ if (fabs(width - size->width) >= 1.0 ||
+ fabs(length - size->length) >= 1.0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" has unexpected dimensions "
+ "(%gx%g)\n"),
+ prefix, size->name, size->width, size->length);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ else if (warn && verbose >= 0)
+ {
+ /*
+ * Lookup the size name in the standard size table...
+ */
+
+ strlcpy(name, size->name, sizeof(name));
+ if ((nameptr = strchr(name, '.')) != NULL)
+ *nameptr = '\0';
+
+ if (!bsearch(name, adobe_size_names,
+ sizeof(adobe_size_names) /
+ sizeof(adobe_size_names[0]),
+ sizeof(adobe_size_names[0]),
+ (int (*)(const void *, const void *))strcmp))
+ {
+ _cupsLangPrintf(stdout,
+ _(" %s Non-standard size name \"%s\"\n"
+ " REF: Page 187, section B.2.\n"),
+ prefix, size->name);
+ }
+ }
+
+ /*
+ * Verify that the size is defined for both PageSize and PageRegion...
+ */
+
+ if (warn != 2 && !ppdFindChoice(page_size, size->name))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" defined for %s but not for "
+ "%s\n"),
+ prefix, size->name, "PageRegion", "PageSize");
+
+ if (!warn)
+ errors ++;
+ }
+ else if (warn != 2 && !ppdFindChoice(page_region, size->name))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" defined for %s but not for "
+ "%s\n"),
+ prefix, size->name, "PageSize", "PageRegion");
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'check_translations()' - Check translations in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_translations(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int j; /* Looping var */
+ ppd_attr_t *attr; /* PPD attribute */
+ cups_array_t *languages; /* Array of languages */
+ int langlen; /* Length of language */
+ char *language, /* Current language */
+ keyword[PPD_MAX_NAME], /* Localization keyword (full) */
+ llkeyword[PPD_MAX_NAME],/* Localization keyword (base) */
+ ckeyword[PPD_MAX_NAME], /* Custom option keyword (full) */
+ cllkeyword[PPD_MAX_NAME];
+ /* Custom option keyword (base) */
+ ppd_option_t *option; /* Standard UI option */
+ ppd_coption_t *coption; /* Custom option */
+ ppd_cparam_t *cparam; /* Custom parameter */
+ char ll[3]; /* Base language */
+ const char *prefix; /* WARN/FAIL prefix */
+ const char *text; /* Pointer into UI text */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ if ((languages = _ppdGetLanguages(ppd)) != NULL)
+ {
+ /*
+ * This file contains localizations, check them...
+ */
+
+ for (language = (char *)cupsArrayFirst(languages);
+ language;
+ language = (char *)cupsArrayNext(languages))
+ {
+ langlen = (int)strlen(language);
+ if (langlen != 2 && langlen != 5)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad language \"%s\"\n"),
+ prefix, language);
+
+ if (!warn)
+ errors ++;
+
+ continue;
+ }
+
+ if (!strcmp(language, "en"))
+ continue;
+
+ strlcpy(ll, language, sizeof(ll));
+
+ /*
+ * Loop through all options and choices...
+ */
+
+ for (option = ppdFirstOption(ppd);
+ option;
+ option = ppdNextOption(ppd))
+ {
+ if (!strcmp(option->keyword, "PageRegion"))
+ continue;
+
+ snprintf(keyword, sizeof(keyword), "%s.Translation", language);
+ snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll);
+
+ if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL &&
+ (attr = ppdFindAttr(ppd, llkeyword, option->keyword)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing \"%s\" translation "
+ "string for option %s\n"),
+ prefix, language, option->keyword);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (!valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" translation "
+ "string for option %s\n"),
+ prefix, language, option->keyword);
+
+ if (!warn)
+ errors ++;
+ }
+
+ snprintf(keyword, sizeof(keyword), "%s.%s", language,
+ option->keyword);
+ snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll,
+ option->keyword);
+
+ for (j = 0; j < option->num_choices; j ++)
+ {
+ /*
+ * First see if this choice is a number; if so, don't require
+ * translation...
+ */
+
+ for (text = option->choices[j].text; *text; text ++)
+ if (!strchr("0123456789-+.", *text))
+ break;
+
+ if (!*text)
+ continue;
+
+ /*
+ * Check custom choices differently...
+ */
+
+ if (!strcasecmp(option->choices[j].choice, "Custom") &&
+ (coption = ppdFindCustomOption(ppd,
+ option->keyword)) != NULL)
+ {
+ snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
+ language, option->keyword);
+
+ if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
+ !valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" "
+ "translation string for option %s, "
+ "choice %s\n"),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
+ "True");
+
+ if (!warn)
+ errors ++;
+ }
+
+ if (strcasecmp(option->keyword, "PageSize"))
+ {
+ for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+ cparam;
+ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+ {
+ snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
+ language, option->keyword);
+ snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s",
+ ll, option->keyword);
+
+ if ((attr = ppdFindAttr(ppd, ckeyword,
+ cparam->name)) == NULL &&
+ (attr = ppdFindAttr(ppd, cllkeyword,
+ cparam->name)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing \"%s\" "
+ "translation string for option %s, "
+ "choice %s\n"),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
+ cparam->name);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (!valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" "
+ "translation string for option %s, "
+ "choice %s\n"),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
+ cparam->name);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+ }
+ else if ((attr = ppdFindAttr(ppd, keyword,
+ option->choices[j].choice)) == NULL &&
+ (attr = ppdFindAttr(ppd, llkeyword,
+ option->choices[j].choice)) == NULL)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing \"%s\" "
+ "translation string for option %s, "
+ "choice %s\n"),
+ prefix, language, option->keyword,
+ option->choices[j].choice);
+
+ if (!warn)
+ errors ++;
+ }
+ else if (!valid_utf8(attr->text))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Bad UTF-8 \"%s\" "
+ "translation string for option %s, "
+ "choice %s\n"),
+ prefix, language, option->keyword,
+ option->choices[j].choice);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ }
+ }
+
+ /*
+ * Verify that we have the base language for each localized one...
+ */
+
+ for (language = (char *)cupsArrayFirst(languages);
+ language;
+ language = (char *)cupsArrayNext(languages))
+ if (language[2])
+ {
+ /*
+ * Lookup the base language...
+ */
+
+ cupsArraySave(languages);
+
+ strlcpy(ll, language, sizeof(ll));
+
+ if (!cupsArrayFind(languages, ll) &&
+ strcmp(ll, "zh") && strcmp(ll, "en"))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s No base translation \"%s\" "
+ "is included in file\n"), prefix, ll);
+
+ if (!warn)
+ errors ++;
+ }
+
+ cupsArrayRestore(languages);
+ }
+
+ /*
+ * Free memory used for the languages...
+ */
+
+ _ppdFreeLanguages(languages);
+ }
+
+ return (errors);
+}
+
+
+/*
+ * 'show_conflicts()' - Show option conflicts in a PPD file.
+ */
+
+static void
+show_conflicts(ppd_file_t *ppd) /* I - PPD to check */
+{
+ int i, j; /* Looping variables */
+ ppd_const_t *c; /* Current constraint */
+ ppd_option_t *o1, *o2; /* Options */
+ ppd_choice_t *c1, *c2; /* Choices */
+
+
+ /*
+ * Loop through all of the UI constraints and report any options
+ * that conflict...
+ */
+
+ for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+ {
+ /*
+ * Grab pointers to the first option...
+ */
+
+ o1 = ppdFindOption(ppd, c->option1);
+
+ if (o1 == NULL)
+ continue;
+ else if (c->choice1[0] != '\0')
+ {
+ /*
+ * This constraint maps to a specific choice.
+ */
+
+ c1 = ppdFindChoice(o1, c->choice1);
+ }
+ else
+ {
+ /*
+ * This constraint applies to any choice for this option.
+ */
+
+ for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
+ if (c1->marked)
+ break;
+
+ if (j == 0 ||
+ !strcasecmp(c1->choice, "None") ||
+ !strcasecmp(c1->choice, "Off") ||
+ !strcasecmp(c1->choice, "False"))
+ c1 = NULL;
+ }
+
+ /*
+ * Grab pointers to the second option...
+ */
+
+ o2 = ppdFindOption(ppd, c->option2);
+
+ if (o2 == NULL)
+ continue;
+ else if (c->choice2[0] != '\0')
+ {
+ /*
+ * This constraint maps to a specific choice.
+ */
+
+ c2 = ppdFindChoice(o2, c->choice2);
+ }
+ else
+ {
+ /*
+ * This constraint applies to any choice for this option.
+ */
+
+ for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
+ if (c2->marked)
+ break;
+
+ if (j == 0 ||
+ !strcasecmp(c2->choice, "None") ||
+ !strcasecmp(c2->choice, "Off") ||
+ !strcasecmp(c2->choice, "False"))
+ c2 = NULL;
+ }
+
+ /*
+ * If both options are marked then there is a conflict...
+ */
+
+ if (c1 != NULL && c1->marked && c2 != NULL && c2->marked)
+ _cupsLangPrintf(stdout,
+ _(" WARN \"%s %s\" conflicts with \"%s %s\"\n"
+ " (constraint=\"%s %s %s %s\")\n"),
+ o1->keyword, c1->choice, o2->keyword, c2->choice,
+ c->option1, c->choice1, c->option2, c->choice2);
+ }
+}
+
+
+/*
+ * 'test_raster()' - Test PostScript commands for raster printers.
+ */
+
+static int /* O - 1 on success, 0 on failure */
+test_raster(ppd_file_t *ppd, /* I - PPD file */
+ int verbose) /* I - Verbosity */
+{
+ cups_page_header2_t header; /* Page header */
+
+
+ ppdMarkDefaults(ppd);
+ if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0))
+ {
+ if (!verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Default option code cannot be "
+ "interpreted: %s\n"), cupsRasterErrorString());
+
+ return (0);
+ }
+
+ /*
+ * Try a test of custom page size code, if available...
+ */
+
+ if (!ppdPageSize(ppd, "Custom.612x792"))
+ return (1);
+
+ ppdMarkOption(ppd, "PageSize", "Custom.612x792");
+
+ if (cupsRasterInterpretPPD(&header, ppd, 0, NULL, 0))
+ {
+ if (!verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" **FAIL** Default option code cannot be "
+ "interpreted: %s\n"), cupsRasterErrorString());
+
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'usage()' - Show program usage...
+ */
+
+static void
+usage(void)
+{
+ _cupsLangPuts(stdout,
+ _("Usage: cupstestppd [options] filename1.ppd[.gz] "
+ "[... filenameN.ppd[.gz]]\n"
+ " program | cupstestppd [options] -\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " -I {filters,profiles}\n"
+ " Ignore missing files\n"
+ " -R root-directory Set alternate root\n"
+ " -W {all,none,constraints,defaults,duplex,filters,"
+ "profiles,sizes,translations}\n"
+ " Issue warnings instead of errors\n"
+ " -q Run silently\n"
+ " -r Use 'relaxed' open mode\n"
+ " -v Be slightly verbose\n"
+ " -vv Be very verbose\n"));
exit(ERROR_USAGE);
}
+/*
+ * 'valid_path()' - Check whether a path has the correct capitalization.
+ */
+
+static int /* O - Errors found */
+valid_path(const char *keyword, /* I - Keyword using path */
+ const char *path, /* I - Path to check */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ cups_dir_t *dir; /* Current directory */
+ cups_dentry_t *dentry; /* Current directory entry */
+ char temp[1024], /* Temporary path */
+ *ptr; /* Pointer into temporary path */
+ const char *prefix; /* WARN/FAIL prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * Loop over the components of the path, checking that the entry exists with
+ * the same capitalization...
+ */
+
+ strlcpy(temp, path, sizeof(temp));
+
+ while ((ptr = strrchr(temp, '/')) != NULL)
+ {
+ /*
+ * Chop off the trailing component so temp == dirname and ptr == basename.
+ */
+
+ *ptr++ = '\0';
+
+ /*
+ * Try opening the directory containing the base name...
+ */
+
+ if (temp[0])
+ dir = cupsDirOpen(temp);
+ else
+ dir = cupsDirOpen("/");
+
+ if (!dir)
+ dentry = NULL;
+ else
+ {
+ while ((dentry = cupsDirRead(dir)) != NULL)
+ {
+ if (!strcmp(dentry->filename, ptr))
+ break;
+ }
+
+ cupsDirClose(dir);
+ }
+
+ /*
+ * Display an error if the filename doesn't exist with the same
+ * capitalization...
+ */
+
+ if (!dentry)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s %s file \"%s\" has the wrong "
+ "capitalization\n"), prefix, keyword, path);
+
+ if (!warn)
+ errors ++;
+
+ break;
+ }
+ }
+
+ return (errors);
+}
+
+
/*
* 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
*/
-int /* O - 1 if valid, 0 if not */
+static int /* O - 1 if valid, 0 if not */
valid_utf8(const char *s) /* I - String to check */
{
while (*s)
/*
- * End of "$Id: cupstestppd.c 6430 2007-04-02 14:01:55Z mike $".
+ * End of "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $".
*/