X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=systemv%2Fcupstestppd.c;h=0a7ae4b3b6ca8eec34113d30f3434601d5db1636;hp=6f013c56a503e5bf5b231483fc4e1489d56370d8;hb=4d301e694f72b03ab2b6c8189387bd7076a3a2ea;hpb=b94498cfba64422f0f21181b0c51cc0bed7c7d92 diff --git a/systemv/cupstestppd.c b/systemv/cupstestppd.c index 6f013c56a..0a7ae4b3b 100644 --- a/systemv/cupstestppd.c +++ b/systemv/cupstestppd.c @@ -1,25 +1,16 @@ /* - * "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z 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. * @@ -27,10 +18,23 @@ * * 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. */ /* @@ -39,10 +43,16 @@ #include #include +#include +#include #include +#include #include #include -#include +#include +#ifdef WIN32 +# define X_OK 0 +#endif /* WIN32 */ /* @@ -55,8 +65,11 @@ enum WARN_CONSTRAINTS = 1, WARN_DEFAULTS = 2, WARN_FILTERS = 4, - WARN_TRANSLATIONS = 8, - WARN_ALL = 15 + WARN_PROFILES = 8, + WARN_TRANSLATIONS = 16, + WARN_DUPLEX = 32, + WARN_SIZES = 64, + WARN_ALL = 127 }; @@ -87,19 +100,204 @@ enum }; +/* + * 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); -int check_constraints(ppd_file_t *ppd, int errors, int verbose, int warn); -int check_defaults(ppd_file_t *ppd, int errors, int verbose, int warn); -int check_filters(ppd_file_t *ppd, const char *root, int errors, - int verbose, int warn); -int check_translations(ppd_file_t *ppd, int errors, int verbose, int warn); -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); /* @@ -117,14 +315,13 @@ main(int argc, /* I - Number of command-line args */ 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 */ - struct stat statbuf; /* File information */ - char pathprog[1024], /* Complete path to program/filter */ - *root; /* Root directory */ + char *root; /* Root directory */ int xdpi, /* X resolution */ ydpi; /* Y resolution */ ppd_file_t *ppd; /* PPD file record */ @@ -135,12 +332,14 @@ main(int argc, /* I - Number of command-line args */ 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... @@ -154,6 +353,7 @@ main(int argc, /* I - Number of command-line args */ status = ERROR_NONE; root = ""; warn = WARN_NONE; + ignore = WARN_NONE; for (i = 1; i < argc; i ++) if (argv[i][0] == '-' && argv[i][1]) @@ -161,6 +361,24 @@ main(int argc, /* I - Number of command-line args */ 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 ++; @@ -170,7 +388,7 @@ main(int argc, /* I - Number of command-line args */ root = argv[i]; break; - case 'W' : /* Turn errors into warnings */ + case 'W' : /* Turn errors into warnings */ i ++; if (i >= argc) @@ -182,8 +400,14 @@ main(int argc, /* I - Number of command-line args */ 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")) @@ -242,10 +466,10 @@ main(int argc, /* I - Number of command-line args */ * Read from stdin... */ - if (verbose >= 0) - printf("(stdin):"); - ppd = ppdOpen(stdin); + + if (verbose >= 0) + printf("%s:", (ppd && ppd->pcfilename) ? ppd->pcfilename : "(stdin)"); } else { @@ -362,7 +586,15 @@ main(int argc, /* I - Number of command-line args */ 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... @@ -394,7 +626,7 @@ main(int argc, /* I - Number of command-line args */ _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); } @@ -430,7 +662,7 @@ main(int argc, /* I - Number of command-line args */ _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); } @@ -487,9 +719,28 @@ main(int argc, /* I - Number of command-line args */ } } - 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 @@ -507,9 +758,33 @@ main(int argc, /* I - Number of command-line args */ 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 @@ -971,7 +1246,8 @@ main(int argc, /* I - Number of command-line args */ 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) { @@ -979,7 +1255,7 @@ main(int argc, /* I - Number of command-line args */ _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); } @@ -989,55 +1265,6 @@ main(int argc, /* I - Number of command-line args */ } } - /* - * 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 (ppdFindChoice(option, "None") == NULL) - { - if (verbose >= 0) - { - 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); - } - - 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")); - - _cupsLangPrintf(stdout, - _(" **FAIL** Bad %s choice %s!\n" - " REF: Page 122, section 5.17\n"), - option->keyword, choice->choice); - } - - errors ++; - } - } - if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) && strcmp(attr->name, "1284DeviceID")) { @@ -1047,7 +1274,7 @@ main(int argc, /* I - Number of command-line args */ _cupsLangPuts(stdout, _(" FAIL\n")); _cupsLangPrintf(stdout, - _(" **FAIL** %s must be 1284DeviceID!\n" + _(" **FAIL** %s must be 1284DeviceID\n" " REF: Page 72, section 5.5\n"), attr->name); } @@ -1055,15 +1282,26 @@ main(int argc, /* I - Number of command-line args */ errors ++; } + errors = check_case(ppd, errors, verbose); + if (!(warn & WARN_CONSTRAINTS)) errors = check_constraints(ppd, errors, verbose, 0); - if (!(warn & WARN_FILTERS)) + 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) { @@ -1080,9 +1318,9 @@ main(int argc, /* I - Number of command-line args */ _cupsLangPuts(stdout, _(" FAIL\n")); if (verbose >= 0) - _cupsLangPrintf(stderr, + _cupsLangPrintf(stdout, _(" **FAIL** Bad LanguageEncoding %s - " - "must be ISOLatin1!\n"), + "must be ISOLatin1\n"), attr->value ? attr->value : "(null)"); errors ++; @@ -1094,9 +1332,9 @@ main(int argc, /* I - Number of command-line args */ _cupsLangPuts(stdout, _(" FAIL\n")); if (verbose >= 0) - _cupsLangPrintf(stderr, + _cupsLangPrintf(stdout, _(" **FAIL** Bad LanguageVersion %s - " - "must be English!\n"), + "must be English\n"), ppd->lang_version ? ppd->lang_version : "(null)"); errors ++; @@ -1129,7 +1367,7 @@ main(int argc, /* I - Number of command-line args */ _cupsLangPrintf(stdout, _(" **FAIL** Default translation " "string for option %s contains 8-bit " - "characters!\n"), + "characters\n"), option->keyword); errors ++; @@ -1156,7 +1394,7 @@ main(int argc, /* I - Number of command-line args */ _cupsLangPrintf(stdout, _(" **FAIL** Default translation " "string for option %s choice %s contains " - "8-bit characters!\n"), + "8-bit characters\n"), option->keyword, option->choices[j].choice); @@ -1180,18 +1418,44 @@ main(int argc, /* I - Number of command-line args */ { check_basics(argv[i]); - if (warn & WARN_CONSTRAINTS) - errors = check_constraints(ppd, errors, verbose, 1); - if (warn & WARN_DEFAULTS) errors = check_defaults(ppd, errors, verbose, 1); - if (warn & WARN_FILTERS) + if (warn & WARN_CONSTRAINTS) + errors = check_constraints(ppd, errors, verbose, 1); + + if ((warn & WARN_FILTERS) && !(ignore & WARN_FILTERS)) errors = check_filters(ppd, root, errors, verbose, 1); + if ((warn & WARN_PROFILES) && !(ignore & WARN_PROFILES)) + errors = check_profiles(ppd, root, errors, verbose, 1); + + if (warn & WARN_SIZES) + errors = check_sizes(ppd, errors, verbose, 1); + else + errors = check_sizes(ppd, errors, verbose, 2); + if (warn & WARN_TRANSLATIONS) errors = check_translations(ppd, errors, verbose, 1); + if (warn & WARN_DUPLEX) + errors = check_duplex(ppd, errors, verbose, 1); + + /* + * Look for legacy duplex keywords... + */ + + if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL) + if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL) + option = ppdFindOption(ppd, "KD03Duplex"); + + if (option) + _cupsLangPrintf(stdout, + _(" 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... */ @@ -1203,9 +1467,12 @@ main(int argc, /* I - Number of command-line args */ 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; @@ -1214,31 +1481,15 @@ main(int argc, /* I - Number of command-line args */ !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); } @@ -1246,7 +1497,7 @@ main(int argc, /* I - Number of command-line args */ 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); } @@ -1324,7 +1575,7 @@ main(int argc, /* I - Number of command-line args */ 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; @@ -1333,7 +1584,7 @@ main(int argc, /* I - Number of command-line args */ 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, @@ -1346,73 +1597,6 @@ main(int argc, /* I - Number of command-line args */ } } - /* - * cupsICCProfile - */ - - for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); - attr != NULL; - attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) - { - if (attr->value) - { - if (attr->value[0] == '/') - snprintf(pathprog, sizeof(pathprog), "%s%s", root, attr->value); - else - { - if ((ptr = getenv("CUPS_DATADIR")) == NULL) - ptr = CUPS_DATADIR; - - if (*ptr == '/' || !*root) - snprintf(pathprog, sizeof(pathprog), "%s%s/profiles/%s", root, - ptr, attr->value); - else - snprintf(pathprog, sizeof(pathprog), "%s/%s/profiles/%s", root, - ptr, attr->value); - } - } - - if (!attr->value || !attr->value[0] || stat(pathprog, &statbuf)) - { - if (verbose >= 0) - _cupsLangPrintf(stdout, - _(" WARN Missing cupsICCProfile " - "file \"%s\"\n"), - !attr->value || !attr->value[0] ? "" : - attr->value); - } - } - -#ifdef __APPLE__ - /* - * APDialogExtension - */ - - for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL); - attr != NULL; - attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL)) - { - if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0) - _cupsLangPrintf(stdout, _(" WARN Missing " - "APDialogExtension file \"%s\"\n"), - attr->value ? attr->value : ""); - } - - /* - * APPrinterIconPath - */ - - for (attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL); - attr != NULL; - attr = ppdFindNextAttr(ppd, "APPrinterIconPath", NULL)) - { - if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0) - _cupsLangPrintf(stdout, _(" WARN Missing " - "APPrinterIconPath file \"%s\"\n"), - attr->value ? attr->value : ""); - } -#endif /* __APPLE__ */ - if (verbose > 0) { if (errors) @@ -1540,6 +1724,14 @@ main(int argc, /* I - Number of command-line args */ } } + _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 ++) @@ -1589,7 +1781,7 @@ main(int argc, /* I - Number of command-line args */ * '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 */ @@ -1629,18 +1821,18 @@ check_basics(const char *filename) /* I - PPD file to check */ 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 ++; @@ -1659,12 +1851,12 @@ check_basics(const char *filename) /* I - PPD file to check */ 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); } @@ -1674,144 +1866,1178 @@ check_basics(const char *filename) /* I - PPD file to check */ * 'check_constraints()' - Check UIConstraints in the PPD file. */ -int /* O - Errors found */ +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 j; /* Looping var */ - ppd_const_t *c; /* Current constraint */ - ppd_option_t *option; /* Standard UI option */ - ppd_option_t *option2; /* Standard UI option */ - const char *prefix; /* WARN/FAIL prefix */ + 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**"; - for (j = ppd->num_consts, c = ppd->consts; j > 0; j --, c ++) + + /* + * See what kind of constraint data we have in the PPD... + */ + + if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL) { - option = ppdFindOption(ppd, c->option1); - option2 = ppdFindOption(ppd, c->option2); + /* + * Check new-style cupsUIConstraints data... + */ - if (!option || !option2) + for (; constattr; + constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL)) { - if (!warn && !errors && !verbose) - _cupsLangPuts(stdout, _(" FAIL\n")); + if (!constattr->value) + { + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); - if (!option) - _cupsLangPrintf(stdout, - _(" %s Missing option %s in " - "UIConstraint \"*%s %s *%s %s\"!\n"), - prefix, c->option1, - c->option1, c->choice1, c->option2, c->choice2); - - if (!option2) _cupsLangPrintf(stdout, - _(" %s Missing option %s in " - "UIConstraint \"*%s %s *%s %s\"!\n"), - prefix, c->option2, - c->option1, c->choice1, c->option2, c->choice2); + _(" %s Empty cupsUIConstraints %s\n"), + prefix, constattr->spec); - if (!warn) - errors ++; + if (!warn) + errors ++; - continue; - } + continue; + } - if (c->choice1[0] && !ppdFindChoice(option, c->choice1)) - { - if (!warn && !errors && !verbose) - _cupsLangPuts(stdout, _(" FAIL\n")); + for (i = 0, vptr = strchr(constattr->value, '*'); + vptr; + i ++, vptr = strchr(vptr + 1, '*')); - _cupsLangPrintf(stdout, - _(" %s Missing choice *%s %s in " - "UIConstraint \"*%s %s *%s %s\"!\n"), - prefix, c->option1, c->choice1, - c->option1, c->choice1, c->option2, c->choice2); + if (i == 0) + { + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); - if (!warn) - errors ++; - } + _cupsLangPrintf(stdout, + _(" %s Bad cupsUIConstraints %s: \"%s\"\n"), + prefix, constattr->spec, constattr->value); - if (c->choice2[0] && !ppdFindChoice(option2, c->choice2)) - { - if (!warn && !errors && !verbose) - _cupsLangPuts(stdout, _(" FAIL\n")); + if (!warn) + errors ++; - _cupsLangPrintf(stdout, - _(" %s Missing choice *%s %s in " - "UIConstraint \"*%s %s *%s %s\"!\n"), - prefix, c->option2, c->choice2, - c->option1, c->choice1, c->option2, c->choice2); + continue; + } - if (!warn) - errors ++; - } - } + cupsArraySave(ppd->sorted_attrs); - return (errors); -} + 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); -/* - * 'check_defaults()' - Check default option keywords in the PPD file. - */ + if (!warn) + errors ++; + } -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 */ + cupsArrayRestore(ppd->sorted_attrs); + num_options = 0; + options = NULL; - prefix = warn ? " WARN " : "**FAIL**"; + for (vptr = strchr(constattr->value, '*'); + vptr; + vptr = strchr(vptr, '*')) + { + /* + * Extract "*Option Choice" or just "*Option"... + */ - for (j = 0; j < ppd->num_attrs; j ++) - { - attr = ppd->attrs[j]; + for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++) + if (ptr < (option + sizeof(option) - 1)) + *ptr++ = *vptr; - if (!strcmp(attr->name, "DefaultColorSpace") || + *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; + } + } + } + + /* + * Resolvers must list at least two options... + */ + + 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 ++; + } + + /* + * Test the resolver... + */ + + if (!cupsResolveConflicts(ppd, NULL, NULL, &num_options, &options)) + { + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); + + _cupsLangPrintf(stdout, + _(" %s cupsUIResolver %s causes a loop\n"), + prefix, constattr->spec); + + if (!warn) + errors ++; + } + + cupsFreeOptions(num_options, options); + } + } + else + { + /* + * Check old-style [Non]UIConstraints data... + */ + + 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")); + + _cupsLangPrintf(stdout, + _(" %s Missing option %s in " + "UIConstraints \"*%s %s *%s %s\"\n"), + prefix, c->option1, + 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->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 (!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 : ""); + + 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) { - if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL && - strcmp(attr->value, "Unknown")) + for (i = 0; i < num_profiles; i ++) + if (hashes[i] == hash) + break; + + if (i < num_profiles) { - /* - * Check that the default option value matches a choice... - */ + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); - for (k = 0; k < option->num_choices; k ++) - if (!strcmp(option->choices[k].choice, attr->value)) - break; + if (verbose >= 0) + _cupsLangPrintf(stdout, + _(" %s cupsICCProfile %s hash value " + "collides with %s\n"), prefix, attr->spec, + specs[i]); - if (k >= option->num_choices) - { - if (!warn && !errors && !verbose) - _cupsLangPuts(stdout, _(" FAIL\n")); + if (!warn) + errors ++; + } + } - if (verbose >= 0) - _cupsLangPrintf(stdout, - _(" %s %s %s does not exist!\n"), - prefix, attr->name, attr->value); + /* + * Remember up to 1000 profiles... + */ - if (!warn) - errors ++; - } - } + if (num_profiles < 1000) + { + hashes[num_profiles] = hash; + specs[num_profiles] = attr->spec; + num_profiles ++; } } @@ -1820,128 +3046,150 @@ check_defaults(ppd_file_t *ppd, /* I - PPD file */ /* - * 'check_filters()' - Check filters in the PPD file. + * 'check_sizes()' - Check media sizes in the PPD file. */ -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? */ +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? */ { - ppd_attr_t *attr; /* PPD attribute */ - const char *ptr; /* Pointer into string */ - struct stat statbuf; /* File information */ - char super[16], /* Super-type for filter */ - type[256], /* Type for filter */ - program[256], /* Program/filter name */ - pathprog[1024]; /* Complete path to program/filter */ - int cost; /* Cost of filter */ + 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**"; - for (attr = ppdFindAttr(ppd, "cupsFilter", NULL); - attr; - attr = ppdFindNextAttr(ppd, "cupsFilter", NULL)) + if ((page_size = ppdFindOption(ppd, "PageSize")) == NULL && warn != 2) { - if (!attr->value || - sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost, - program) != 4) - { - if (!warn && !errors && !verbose) - _cupsLangPuts(stdout, _(" FAIL\n")); + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); - if (verbose >= 0) - _cupsLangPrintf(stdout, - _(" %s Bad cupsFilter value \"%s\"!\n"), - prefix, attr->value ? attr->value : ""); + if (verbose >= 0) + _cupsLangPrintf(stdout, + _(" %s Missing REQUIRED PageSize option\n" + " REF: Page 99, section 5.14.\n"), + prefix); - if (!warn) - errors ++; - } - else + 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")) { - if (program[0] == '/') - snprintf(pathprog, sizeof(pathprog), "%s%s", root, program); - else - { - if ((ptr = getenv("CUPS_SERVERBIN")) == NULL) - ptr = CUPS_SERVERBIN; + /* + * Skip custom page size... + */ - 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); - } + 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 (stat(pathprog, &statbuf)) + 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 Missing cupsFilter " - "file \"%s\"\n"), prefix, program); + _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... + */ - for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL); - attr; - attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL)) - { - if (!attr->value || - sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost, - program) != 4) + 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 Bad cupsPreFilter value \"%s\"!\n"), - prefix, attr->value ? attr->value : ""); + _(" %s Size \"%s\" defined for %s but not for " + "%s\n"), + prefix, size->name, "PageRegion", "PageSize"); if (!warn) - errors ++; + errors ++; } - else + else if (warn != 2 && !ppdFindChoice(page_region, size->name)) { - 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, &statbuf)) - { - if (!warn && !errors && !verbose) - _cupsLangPuts(stdout, _(" FAIL\n")); + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); - if (verbose >= 0) - _cupsLangPrintf(stdout, _(" %s Missing cupsPreFilter " - "file \"%s\"\n"), prefix, program); + if (verbose >= 0) + _cupsLangPrintf(stdout, + _(" %s Size \"%s\" defined for %s but not for " + "%s\n"), + prefix, size->name, "PageSize", "PageRegion"); - if (!warn) - errors ++; - } + if (!warn) + errors ++; } } @@ -1953,7 +3201,7 @@ check_filters(ppd_file_t *ppd, /* I - PPD file */ * 'check_translations()' - Check translations in the PPD file. */ -int /* O - Errors found */ +static int /* O - Errors found */ check_translations(ppd_file_t *ppd, /* I - PPD file */ int errors, /* I - Errors found */ int verbose, /* I - Verbosity level */ @@ -1961,9 +3209,9 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ { int j; /* Looping var */ ppd_attr_t *attr; /* PPD attribute */ - char *languages, /* Copy of attribute value */ - *langstart, /* Start of current language */ - *langptr, /* Pointer into languages */ + 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) */ @@ -1972,56 +3220,33 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ ppd_option_t *option; /* Standard UI option */ 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 */ const char *prefix; /* WARN/FAIL prefix */ + const char *text; /* Pointer into UI text */ prefix = warn ? " WARN " : "**FAIL**"; - if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL && - attr->value) + if ((languages = _ppdGetLanguages(ppd)) != NULL) { /* * This file contains localizations, check them... */ - languages = strdup(attr->value); - langlist = cupsArrayNew((cups_array_func_t)strcmp, NULL); - - for (langptr = languages; *langptr;) + for (language = (char *)cupsArrayFirst(languages); + language; + language = (char *)cupsArrayNext(languages)) { - /* - * Skip leading whitespace... - */ - - while (isspace(*langptr & 255)) - langptr ++; - - if (!*langptr) - break; - - /* - * Find the end of this language name... - */ - - for (langstart = langptr; - *langptr && !isspace(*langptr & 255); - langptr ++); - - if (*langptr) - *langptr++ = '\0'; - - j = strlen(langstart); - if (j != 2 && j != 5) + 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, langstart); + _(" %s Bad language \"%s\"\n"), + prefix, language); if (!warn) errors ++; @@ -2029,9 +3254,10 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ continue; } - cupsArrayAdd(langlist, langstart); + if (!strcmp(language, "en")) + continue; - strlcpy(ll, langstart, sizeof(ll)); + strlcpy(ll, language, sizeof(ll)); /* * Loop through all options and choices... @@ -2041,7 +3267,10 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ option; option = ppdNextOption(ppd)) { - snprintf(keyword, sizeof(keyword), "%s.Translation", langstart); + 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 && @@ -2053,8 +3282,8 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ if (verbose >= 0) _cupsLangPrintf(stdout, _(" %s Missing \"%s\" translation " - "string for option %s!\n"), - prefix, langstart, option->keyword); + "string for option %s\n"), + prefix, language, option->keyword); if (!warn) errors ++; @@ -2067,26 +3296,42 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ if (verbose >= 0) _cupsLangPrintf(stdout, _(" %s Bad UTF-8 \"%s\" translation " - "string for option %s!\n"), - prefix, langstart, option->keyword); + "string for option %s\n"), + prefix, language, option->keyword); if (!warn) errors ++; } - snprintf(keyword, sizeof(keyword), "%s.%s", langstart, + 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", - langstart, option->keyword); + language, option->keyword); if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL && !valid_utf8(attr->text)) @@ -2098,9 +3343,9 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ _cupsLangPrintf(stdout, _(" %s Bad UTF-8 \"%s\" " "translation string for option %s, " - "choice %s!\n"), - prefix, langstart, - ckeyword + 1 + strlen(langstart), + "choice %s\n"), + prefix, language, + ckeyword + 1 + strlen(language), "True"); if (!warn) @@ -2114,7 +3359,7 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ cparam = (ppd_cparam_t *)cupsArrayNext(coption->params)) { snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s", - langstart, option->keyword); + language, option->keyword); snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s", ll, option->keyword); @@ -2130,9 +3375,9 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ _cupsLangPrintf(stdout, _(" %s Missing \"%s\" " "translation string for option %s, " - "choice %s!\n"), - prefix, langstart, - ckeyword + 1 + strlen(langstart), + "choice %s\n"), + prefix, language, + ckeyword + 1 + strlen(language), cparam->name); if (!warn) @@ -2147,9 +3392,9 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ _cupsLangPrintf(stdout, _(" %s Bad UTF-8 \"%s\" " "translation string for option %s, " - "choice %s!\n"), - prefix, langstart, - ckeyword + 1 + strlen(langstart), + "choice %s\n"), + prefix, language, + ckeyword + 1 + strlen(language), cparam->name); if (!warn) @@ -2170,8 +3415,8 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ _cupsLangPrintf(stdout, _(" %s Missing \"%s\" " "translation string for option %s, " - "choice %s!\n"), - prefix, langstart, option->keyword, + "choice %s\n"), + prefix, language, option->keyword, option->choices[j].choice); if (!warn) @@ -2186,8 +3431,8 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ _cupsLangPrintf(stdout, _(" %s Bad UTF-8 \"%s\" " "translation string for option %s, " - "choice %s!\n"), - prefix, langstart, option->keyword, + "choice %s\n"), + prefix, language, option->keyword, option->choices[j].choice); if (!warn) @@ -2201,20 +3446,21 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ * Verify that we have the base language for each localized one... */ - for (langptr = (char *)cupsArrayFirst(langlist); - langptr; - langptr = (char *)cupsArrayNext(langlist)) - if (langptr[2]) + for (language = (char *)cupsArrayFirst(languages); + language; + language = (char *)cupsArrayNext(languages)) + if (language[2]) { /* * Lookup the base language... */ - cupsArraySave(langlist); + cupsArraySave(languages); - strlcpy(ll, langptr, sizeof(ll)); + strlcpy(ll, language, sizeof(ll)); - if (!cupsArrayFind(langlist, ll) && strcmp(ll, "zh")) + if (!cupsArrayFind(languages, ll) && + strcmp(ll, "zh") && strcmp(ll, "en")) { if (!warn && !errors && !verbose) _cupsLangPuts(stdout, _(" FAIL\n")); @@ -2222,21 +3468,20 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ if (verbose >= 0) _cupsLangPrintf(stdout, _(" %s No base translation \"%s\" " - "is included in file!\n"), prefix, ll); + "is included in file\n"), prefix, ll); if (!warn) errors ++; } - cupsArrayRestore(langlist); + cupsArrayRestore(languages); } /* * Free memory used for the languages... */ - cupsArrayDelete(langlist); - free(languages); + _ppdFreeLanguages(languages); } return (errors); @@ -2247,7 +3492,7 @@ check_translations(ppd_file_t *ppd, /* I - PPD file */ * 'show_conflicts()' - Show option conflicts in a PPD file. */ -void +static void show_conflicts(ppd_file_t *ppd) /* I - PPD to check */ { int i, j; /* Looping variables */ @@ -2343,11 +3588,62 @@ show_conflicts(ppd_file_t *ppd) /* I - PPD to check */ } +/* + * '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... */ -void +static void usage(void) { _cupsLangPuts(stdout, @@ -2357,8 +3653,11 @@ usage(void) "\n" "Options:\n" "\n" + " -I {filters,profiles}\n" + " Ignore missing files\n" " -R root-directory Set alternate root\n" - " -W {all,none,constraints,defaults,filters,translations}\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" @@ -2369,11 +3668,94 @@ usage(void) } +/* + * '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) @@ -2446,5 +3828,5 @@ valid_utf8(const char *s) /* I - String to check */ /* - * End of "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $". + * End of "$Id: cupstestppd.c 7807 2008-07-28 21:54:24Z mike $". */