/*
- * "$Id: cupstestppd.c 6927 2007-09-07 16:51:00Z mike $"
+ * "$Id: cupstestppd.c 7637 2008-06-11 17:25:36Z mike $"
*
* PPD test program for the Common UNIX Printing System (CUPS).
*
* Contents:
*
* main() - Main entry for test program.
- * check_basics() - Check for CR LF, mixed line endings, and blank lines.
+ * check_basics() - Check for CR LF, mixed line endings, and blank
+ * lines.
* check_constraints() - Check UIConstraints in the PPD file.
* check_defaults() - Check default option keywords in the PPD file.
* check_filters() - Check filters in the PPD file.
+ * check_profiles() - Check ICC color profiles 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.
#include <cups/string.h>
#include <cups/cups.h>
+#include <cups/ppd-private.h>
#include <cups/i18n.h>
#include <cups/raster.h>
#include <errno.h>
WARN_CONSTRAINTS = 1,
WARN_DEFAULTS = 2,
WARN_FILTERS = 4,
- WARN_TRANSLATIONS = 8,
- WARN_ALL = 15
+ WARN_PROFILES = 8,
+ WARN_TRANSLATIONS = 16,
+ WARN_ALL = 31
};
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_translations(ppd_file_t *ppd, int errors, int verbose,\
int warn);
static void show_conflicts(ppd_file_t *ppd);
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 */
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...
warn |= WARN_DEFAULTS;
else if (!strcmp(argv[i], "filters"))
warn |= WARN_FILTERS;
+ else if (!strcmp(argv[i], "profiles"))
+ warn |= WARN_PROFILES;
else if (!strcmp(argv[i], "translations"))
warn |= WARN_TRANSLATIONS;
else if (!strcmp(argv[i], "all"))
* Read from stdin...
*/
- if (verbose >= 0)
- printf("(stdin):");
-
ppd = ppdOpen(stdin);
+
+ if (verbose >= 0)
+ printf("%s:", (ppd && ppd->pcfilename) ? ppd->pcfilename : "(stdin)");
}
else
{
if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
attr->value)
- ppdversion = (int)(10 * atof(attr->value) + 0.5);
+ ppdversion = (int)(10 * _cupsStrScand(attr->value, NULL, loc) + 0.5);
for (j = 0; j < ppd->num_filters; j ++)
if (strstr(ppd->filters[j], "application/vnd.cups-raster"))
if (!(warn & WARN_FILTERS))
errors = check_filters(ppd, root, errors, verbose, 0);
+ if (!(warn & WARN_PROFILES))
+ errors = check_profiles(ppd, root, errors, verbose, 0);
+
if (!(warn & WARN_TRANSLATIONS))
errors = check_translations(ppd, errors, verbose, 0);
if (warn & WARN_DEFAULTS)
errors = check_defaults(ppd, errors, verbose, 1);
+ if (warn & WARN_PROFILES)
+ errors = check_profiles(ppd, root, errors, verbose, 1);
+
if (warn & WARN_FILTERS)
errors = check_filters(ppd, root, errors, verbose, 1);
}
}
- /*
- * 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] ? "<NULL>" :
- attr->value);
- }
- }
-
#ifdef __APPLE__
/*
* APDialogExtension
attr != NULL;
attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
{
- if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0)
+ if ((!attr->value || access(attr->value, 0)) && verbose >= 0)
_cupsLangPrintf(stdout, _(" WARN Missing "
"APDialogExtension file \"%s\"\n"),
attr->value ? attr->value : "<NULL>");
attr != NULL;
attr = ppdFindNextAttr(ppd, "APPrinterIconPath", NULL))
{
- if ((!attr->value || stat(attr->value, &statbuf)) && verbose >= 0)
+ if ((!attr->value || access(attr->value, 0)) && verbose >= 0)
_cupsLangPrintf(stdout, _(" WARN Missing "
"APPrinterIconPath file \"%s\"\n"),
attr->value ? attr->value : "<NULL>");
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;
}
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 */
- struct stat statbuf; /* File information */
char super[16], /* Super-type for filter */
type[256], /* Type for filter */
- program[256], /* Program/filter name */
+ program[1024], /* 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))
+ for (i = 0; i < ppd->num_filters; i ++)
{
- if (!attr->value ||
- sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
- program) != 4)
+ 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, attr->value ? attr->value : "");
+ prefix, ppd->filters[i]);
if (!warn)
errors ++;
program);
}
- if (stat(pathprog, &statbuf))
+ if (access(pathprog, X_OK))
{
if (!warn && !errors && !verbose)
_cupsLangPuts(stdout, _(" FAIL\n"));
attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
{
if (!attr->value ||
- sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
- program) != 4)
+ sscanf(attr->value, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
+ &cost, program) != 4)
{
if (!warn && !errors && !verbose)
_cupsLangPuts(stdout, _(" FAIL\n"));
program);
}
- if (stat(pathprog, &statbuf))
+ if (access(pathprog, X_OK))
{
if (!warn && !errors && !verbose)
_cupsLangPuts(stdout, _(" FAIL\n"));
}
+/*
+ * '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 */
+ 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 (access(filename, 0))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing cupsICCProfile "
+ "file \"%s\"!\n"), prefix, attr->value);
+
+ if (!warn)
+ errors ++;
+ }
+
+ /*
+ * Check for hash collisions...
+ */
+
+ hash = _ppdHashName(attr->spec);
+
+ if (num_profiles > 0)
+ {
+ for (i = 0; i < num_profiles; i ++)
+ if (hashes[i] == hash)
+ break;
+
+ if (i < num_profiles)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s cupsICCProfile %s hash value "
+ "collides with %s!\n"), prefix, attr->spec,
+ specs[i]);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ /*
+ * Remember up to 1000 profiles...
+ */
+
+ if (num_profiles < 1000)
+ {
+ hashes[num_profiles] = hash;
+ specs[num_profiles] = attr->spec;
+ num_profiles ++;
+ }
+ }
+
+ return (errors);
+}
+
+
/*
* 'check_translations()' - Check translations in the 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) */
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)
+ if ((languages = _ppdGetLanguages(ppd)) != NULL)
{
/*
* This file contains localizations, check them...
*/
- if ((languages = strdup(attr->value)) == NULL)
- return (1);
-
- 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 = 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);
+ prefix, language);
if (!warn)
errors ++;
continue;
}
- if (!strcmp(langstart, "en"))
+ if (!strcmp(language, "en"))
continue;
- cupsArrayAdd(langlist, langstart);
-
- strlcpy(ll, langstart, sizeof(ll));
+ strlcpy(ll, language, sizeof(ll));
/*
* Loop through all options and choices...
if (!strcmp(option->keyword, "PageRegion"))
continue;
- snprintf(keyword, sizeof(keyword), "%s.Translation", langstart);
+ snprintf(keyword, sizeof(keyword), "%s.Translation", language);
snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll);
if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL &&
_cupsLangPrintf(stdout,
_(" %s Missing \"%s\" translation "
"string for option %s!\n"),
- prefix, langstart, option->keyword);
+ prefix, language, option->keyword);
if (!warn)
errors ++;
_cupsLangPrintf(stdout,
_(" %s Bad UTF-8 \"%s\" translation "
"string for option %s!\n"),
- prefix, langstart, option->keyword);
+ 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);
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))
_(" %s Bad UTF-8 \"%s\" "
"translation string for option %s, "
"choice %s!\n"),
- prefix, langstart,
- ckeyword + 1 + strlen(langstart),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
"True");
if (!warn)
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);
_(" %s Missing \"%s\" "
"translation string for option %s, "
"choice %s!\n"),
- prefix, langstart,
- ckeyword + 1 + strlen(langstart),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
cparam->name);
if (!warn)
_(" %s Bad UTF-8 \"%s\" "
"translation string for option %s, "
"choice %s!\n"),
- prefix, langstart,
- ckeyword + 1 + strlen(langstart),
+ prefix, language,
+ ckeyword + 1 + strlen(language),
cparam->name);
if (!warn)
_(" %s Missing \"%s\" "
"translation string for option %s, "
"choice %s!\n"),
- prefix, langstart, option->keyword,
+ prefix, language, option->keyword,
option->choices[j].choice);
if (!warn)
_(" %s Bad UTF-8 \"%s\" "
"translation string for option %s, "
"choice %s!\n"),
- prefix, langstart, option->keyword,
+ prefix, language, option->keyword,
option->choices[j].choice);
if (!warn)
* 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"))
{
if (!warn && !errors && !verbose)
_cupsLangPuts(stdout, _(" FAIL\n"));
errors ++;
}
- cupsArrayRestore(langlist);
+ cupsArrayRestore(languages);
}
/*
* Free memory used for the languages...
*/
- cupsArrayDelete(langlist);
- free(languages);
+ _ppdFreeLanguages(languages);
}
return (errors);
/*
- * End of "$Id: cupstestppd.c 6927 2007-09-07 16:51:00Z mike $".
+ * End of "$Id: cupstestppd.c 7637 2008-06-11 17:25:36Z mike $".
*/