X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=systemv%2Fcupstestppd.c;h=6f013c56a503e5bf5b231483fc4e1489d56370d8;hb=b94498cfba64422f0f21181b0c51cc0bed7c7d92;hp=068a4b81be00e2ac7ff615bebefc14a73a0d5f03;hpb=f7deaa1a21758ec90bf23314af018481ea8aea7f;p=thirdparty%2Fcups.git diff --git a/systemv/cupstestppd.c b/systemv/cupstestppd.c index 068a4b81b..6f013c56a 100644 --- a/systemv/cupstestppd.c +++ b/systemv/cupstestppd.c @@ -1,5 +1,5 @@ /* - * "$Id: cupstestppd.c 6322 2007-03-08 19:25:26Z mike $" + * "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $" * * PPD test program for the Common UNIX Printing System (CUPS). * @@ -42,6 +42,22 @@ #include #include #include +#include + + +/* + * Error warning overrides... + */ + +enum +{ + WARN_NONE = 0, + WARN_CONSTRAINTS = 1, + WARN_DEFAULTS = 2, + WARN_FILTERS = 4, + WARN_TRANSLATIONS = 8, + WARN_ALL = 15 +}; /* @@ -76,39 +92,49 @@ enum */ 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); + /* * '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 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 */ + 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 */ static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" }; static char *sections[] = { "ANY", "DOCUMENT", "EXIT", "JCL", "PAGE", "PROLOG" }; @@ -126,6 +152,8 @@ main(int argc, /* I - Number of command-line arguments */ ppd = NULL; files = 0; status = ERROR_NONE; + root = ""; + warn = WARN_NONE; for (i = 1; i < argc; i ++) if (argv[i][0] == '-' && argv[i][1]) @@ -133,6 +161,37 @@ main(int argc, /* I - Number of command-line arguments */ for (opt = argv[i] + 1; *opt; opt ++) switch (*opt) { + 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], "filters")) + warn |= WARN_FILTERS; + 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) { @@ -309,48 +368,8 @@ main(int argc, /* I - Number of command-line arguments */ * 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) { @@ -360,14 +379,14 @@ main(int argc, /* I - Number of command-line arguments */ _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) { @@ -375,10 +394,10 @@ main(int argc, /* I - Number of command-line arguments */ _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 ++; } @@ -396,14 +415,14 @@ main(int argc, /* I - Number of command-line arguments */ _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) { @@ -411,10 +430,10 @@ main(int argc, /* I - Number of command-line arguments */ _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 ++; } @@ -430,8 +449,8 @@ main(int argc, /* I - Number of command-line arguments */ 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) { @@ -439,16 +458,16 @@ main(int argc, /* I - Number of command-line arguments */ _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 @@ -459,10 +478,10 @@ main(int argc, /* I - Number of command-line arguments */ _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 ++; } @@ -566,6 +585,22 @@ main(int argc, /* I - Number of command-line arguments */ 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")); } @@ -1003,332 +1038,160 @@ main(int argc, /* I - Number of command-line arguments */ } } - if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL && - attr->value) + if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) && + strcmp(attr->name, "1284DeviceID")) { - /* - * This file contains localizations, check them... - */ + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); - 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 */ + _cupsLangPrintf(stdout, + _(" **FAIL** %s must be 1284DeviceID!\n" + " REF: Page 72, section 5.5\n"), + attr->name); + } + errors ++; + } - languages = strdup(attr->value); - for (langptr = languages; *langptr;) - { - /* - * Skip leading whitespace... - */ + if (!(warn & WARN_CONSTRAINTS)) + errors = check_constraints(ppd, errors, verbose, 0); - while (isspace(*langptr & 255)) - langptr ++; + if (!(warn & WARN_FILTERS)) + errors = check_filters(ppd, root, errors, verbose, 0); - if (!*langptr) - break; + if (!(warn & WARN_TRANSLATIONS)) + errors = check_translations(ppd, errors, verbose, 0); - /* - * Find the end of this language name... - */ + if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL && + attr->value) + { + /* + * This file contains localizations, check for conformance of the + * base translation... + */ + + if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL) + { + 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(stderr, + _(" **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")); - _cupsLangPrintf(stdout, - _(" **FAIL** Bad language \"%s\"!\n"), - langstart); - } + if (verbose >= 0) + _cupsLangPrintf(stderr, + _(" **FAIL** Bad LanguageVersion %s - " + "must be English!\n"), + ppd->lang_version ? ppd->lang_version : "(null)"); - errors ++; - continue; + errors ++; } - - /* + + /* * 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"), 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) - { - 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), - "True"); - } - - 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), - "True"); - } - - 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", - 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 (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, " - "choice %s!\n"), - langstart, option->keyword, - option->choices[j].choice); - } + for (ptr = option->choices[j].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, " - "choice %s!\n"), - langstart, option->keyword, - option->choices[j].choice); - } - - errors ++; - } - - for (ptr = option->choices[j].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 choice %s contains " "8-bit characters!\n"), option->keyword, option->choices[j].choice); - } errors ++; } - } + } } - } - } - - 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")); - - _cupsLangPrintf(stdout, - _(" **FAIL** %s must be 1284DeviceID!\n" - " REF: Page 72, section 5.5\n"), - attr->name); - } - - errors ++; - } + /* + * Final pass/fail notification... + */ if (errors) status = ERROR_CONFORMANCE; else if (!verbose) _cupsLangPuts(stdout, _(" PASS\n")); - + if (verbose >= 0) { 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) + errors = check_filters(ppd, root, errors, verbose, 1); + + if (warn & WARN_TRANSLATIONS) + errors = check_translations(ppd, errors, verbose, 1); + /* * Look for default keywords with no corresponding option... */ @@ -1483,25 +1346,92 @@ main(int argc, /* I - Number of command-line arguments */ } } - if (verbose > 0) + /* + * cupsICCProfile + */ + + for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); + attr != NULL; + attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL)) { - if (errors) - _cupsLangPrintf(stdout, _(" %d ERRORS FOUND\n"), errors); - else - _cupsLangPuts(stdout, _(" NO ERRORS FOUND\n")); + 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__ /* - * Then list the options, if "-v" was provided... - */ + * APDialogExtension + */ - if (verbose > 1) + for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL); + attr != NULL; + attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL)) { - _cupsLangPrintf(stdout, - "\n" - " language_level = %d\n" - " color_device = %s\n" - " variable_sizes = %s\n" + 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) + _cupsLangPrintf(stdout, _(" %d ERRORS FOUND\n"), errors); + else + _cupsLangPuts(stdout, _(" NO ERRORS FOUND\n")); + } + + /* + * Then list the options, if "-v" was provided... + */ + + if (verbose > 1) + { + _cupsLangPrintf(stdout, + "\n" + " language_level = %d\n" + " color_device = %s\n" + " variable_sizes = %s\n" " landscape = %d\n", ppd->language_level, ppd->color_device ? "TRUE" : "FALSE", @@ -1740,6 +1670,579 @@ check_basics(const char *filename) /* I - PPD file to check */ } +/* + * 'check_constraints()' - Check UIConstraints in the PPD file. + */ + +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 */ + + + prefix = warn ? " WARN " : "**FAIL**"; + + for (j = ppd->num_consts, c = ppd->consts; j > 0; j --, c ++) + { + option = ppdFindOption(ppd, c->option1); + option2 = ppdFindOption(ppd, c->option2); + + if (!option || !option2) + { + 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); + + if (!warn) + errors ++; + + continue; + } + + if (c->choice1[0] && !ppdFindChoice(option, c->choice1)) + { + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); + + _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 (!warn) + errors ++; + } + + if (c->choice2[0] && !ppdFindChoice(option2, c->choice2)) + { + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); + + _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); + + if (!warn) + errors ++; + } + } + + return (errors); +} + + +/* + * 'check_defaults()' - Check default option keywords in the PPD file. + */ + +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, "DefaultImageableArea") || + !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_filters()' - Check filters 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? */ +{ + 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 */ + const char *prefix; /* WARN/FAIL prefix */ + + + prefix = warn ? " WARN " : "**FAIL**"; + + for (attr = ppdFindAttr(ppd, "cupsFilter", NULL); + attr; + attr = ppdFindNextAttr(ppd, "cupsFilter", NULL)) + { + if (!attr->value || + sscanf(attr->value, "%15[^/]/%255s%d%255s", 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, attr->value ? attr->value : ""); + + if (!warn) + errors ++; + } + else + { + 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 (verbose >= 0) + _cupsLangPrintf(stdout, _(" %s Missing cupsFilter " + "file \"%s\"\n"), prefix, program); + + if (!warn) + errors ++; + } + } + } + + 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) + { + 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 (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 (verbose >= 0) + _cupsLangPrintf(stdout, _(" %s Missing cupsPreFilter " + "file \"%s\"\n"), prefix, program); + + if (!warn) + errors ++; + } + } + } + + return (errors); +} + + +/* + * 'check_translations()' - Check translations in the PPD file. + */ + +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 */ + char *languages, /* Copy of attribute value */ + *langstart, /* Start of current language */ + *langptr, /* Pointer into languages */ + 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 */ + cups_array_t *langlist; /* List of languages so far */ + char ll[3]; /* Base language */ + const char *prefix; /* WARN/FAIL prefix */ + + + prefix = warn ? " WARN " : "**FAIL**"; + + if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL && + attr->value) + { + /* + * This file contains localizations, check them... + */ + + languages = strdup(attr->value); + langlist = cupsArrayNew((cups_array_func_t)strcmp, NULL); + + for (langptr = languages; *langptr;) + { + /* + * 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) + { + if (!warn && !errors && !verbose) + _cupsLangPuts(stdout, _(" FAIL\n")); + + if (verbose >= 0) + _cupsLangPrintf(stdout, + _(" %s Bad language \"%s\"!\n"), + prefix, langstart); + + if (!warn) + errors ++; + + continue; + } + + cupsArrayAdd(langlist, langstart); + + strlcpy(ll, langstart, sizeof(ll)); + + /* + * Loop through all options and choices... + */ + + for (option = ppdFirstOption(ppd); + option; + option = ppdNextOption(ppd)) + { + snprintf(keyword, sizeof(keyword), "%s.Translation", langstart); + 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, langstart, 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, langstart, option->keyword); + + if (!warn) + errors ++; + } + + snprintf(keyword, sizeof(keyword), "%s.%s", langstart, + option->keyword); + snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll, + option->keyword); + + 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 (!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, langstart, + ckeyword + 1 + strlen(langstart), + "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", + langstart, 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, langstart, + ckeyword + 1 + strlen(langstart), + 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, langstart, + ckeyword + 1 + strlen(langstart), + 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, langstart, 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, langstart, option->keyword, + option->choices[j].choice); + + if (!warn) + errors ++; + } + } + } + } + + /* + * Verify that we have the base language for each localized one... + */ + + for (langptr = (char *)cupsArrayFirst(langlist); + langptr; + langptr = (char *)cupsArrayNext(langlist)) + if (langptr[2]) + { + /* + * Lookup the base language... + */ + + cupsArraySave(langlist); + + strlcpy(ll, langptr, sizeof(ll)); + + if (!cupsArrayFind(langlist, ll) && strcmp(ll, "zh")) + { + 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(langlist); + } + + /* + * Free memory used for the languages... + */ + + cupsArrayDelete(langlist); + free(languages); + } + + return (errors); +} + + /* * 'show_conflicts()' - Show option conflicts in a PPD file. */ @@ -1848,9 +2351,19 @@ void usage(void) { _cupsLangPuts(stdout, - _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] " + _("Usage: cupstestppd [options] filename1.ppd[.gz] " "[... filenameN.ppd[.gz]]\n" - " program | cupstestppd [-q] [-r] [-v[v]] -\n")); + " program | cupstestppd [options] -\n" + "\n" + "Options:\n" + "\n" + " -R root-directory Set alternate root\n" + " -W {all,none,constraints,defaults,filters,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); } @@ -1933,5 +2446,5 @@ valid_utf8(const char *s) /* I - String to check */ /* - * End of "$Id: cupstestppd.c 6322 2007-03-08 19:25:26Z mike $". + * End of "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $". */