]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - systemv/cupstestppd.c
Merge changes from CUPS 1.5svn-r8849.
[thirdparty/cups.git] / systemv / cupstestppd.c
index 4a619ebcad57a03c800dbe6dafacaf290ef8ca7c..0a7ae4b3b6ca8eec34113d30f3434601d5db1636 100644 (file)
@@ -50,6 +50,9 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <math.h>
+#ifdef WIN32
+#  define X_OK 0
+#endif /* WIN32 */
 
 
 /*
@@ -97,6 +100,17 @@ 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)...
  */
@@ -301,6 +315,7 @@ 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 */
@@ -338,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])
@@ -345,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 ++;
 
@@ -354,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)
@@ -592,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);
        }
@@ -628,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);
        }
@@ -1221,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);
             }
@@ -1240,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);
         }
@@ -1253,10 +1287,10 @@ main(int  argc,                         /* I - Number of command-line args */
       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))
+      if (!(warn & WARN_PROFILES) && !(ignore & WARN_PROFILES))
         errors = check_profiles(ppd, root, errors, verbose, 0);
 
       if (!(warn & WARN_SIZES))
@@ -1286,7 +1320,7 @@ main(int  argc,                           /* I - Number of command-line args */
             if (verbose >= 0)
              _cupsLangPrintf(stdout,
                              _("      **FAIL**  Bad LanguageEncoding %s - "
-                               "must be ISOLatin1!\n"),
+                               "must be ISOLatin1\n"),
                              attr->value ? attr->value : "(null)");
 
             errors ++;
@@ -1300,7 +1334,7 @@ main(int  argc,                           /* I - Number of command-line args */
             if (verbose >= 0)
              _cupsLangPrintf(stdout,
                              _("      **FAIL**  Bad LanguageVersion %s - "
-                               "must be English!\n"),
+                               "must be English\n"),
                              ppd->lang_version ? ppd->lang_version : "(null)");
 
             errors ++;
@@ -1333,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 ++;
@@ -1360,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);
 
@@ -1384,18 +1418,18 @@ 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_PROFILES)
-         errors = check_profiles(ppd, root, errors, verbose, 1);
+       if (warn & WARN_CONSTRAINTS)
+         errors = check_constraints(ppd, errors, verbose, 1);
 
-       if (warn & WARN_FILTERS)
+       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
@@ -1418,7 +1452,7 @@ main(int  argc,                           /* I - Number of command-line args */
        if (option)
          _cupsLangPrintf(stdout,
                          _("        WARN    Duplex option keyword %s may not "
-                           "work as expected and should be named Duplex!\n"
+                           "work as expected and should be named Duplex\n"
                            "                REF: Page 122, section 5.17\n"),
                          option->keyword);
 
@@ -1447,7 +1481,7 @@ 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);
        }
 
@@ -1455,7 +1489,7 @@ main(int  argc,                           /* I - Number of command-line args */
        if (ppdConflicts(ppd))
        {
          _cupsLangPuts(stdout,
-                       _("        WARN    Default choices conflicting!\n"));
+                       _("        WARN    Default choices conflicting\n"));
 
           show_conflicts(ppd);
         }
@@ -1463,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);
        }
@@ -1541,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;
@@ -1550,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,
@@ -1798,7 +1832,7 @@ check_basics(const char *filename)        /* I - PPD file to check */
       
       if (col > 0 && whitespace)
        _cupsLangPrintf(stdout,
-                       _("        WARN    Line %d only contains whitespace!\n"),
+                       _("        WARN    Line %d only contains whitespace\n"),
                        linenum);
 
       linenum ++;
@@ -1817,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);
 }
@@ -1875,7 +1909,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  Empty cupsUIConstraints %s!\n"),
+                       _("      %s  Empty cupsUIConstraints %s\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -1894,7 +1928,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsUIConstraints %s: \"%s\"!\n"),
+                       _("      %s  Bad cupsUIConstraints %s: \"%s\"\n"),
                        prefix, constattr->spec, constattr->value);
 
        if (!warn)
@@ -1912,7 +1946,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  Missing cupsUIResolver %s!\n"),
+                       _("      %s  Missing cupsUIResolver %s\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -1965,7 +1999,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
          _cupsLangPrintf(stdout,
                          _("      %s  Missing option %s in "
-                           "cupsUIConstraints %s: \"%s\"!\n"),
+                           "cupsUIConstraints %s: \"%s\"\n"),
                          prefix, option, constattr->spec, constattr->value);
          
          if (!warn)
@@ -1981,7 +2015,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
          _cupsLangPrintf(stdout,
                          _("      %s  Missing choice *%s %s in "
-                           "cupsUIConstraints %s: \"%s\"!\n"),
+                           "cupsUIConstraints %s: \"%s\"\n"),
                          prefix, option, choice, constattr->spec,
                          constattr->value);
 
@@ -2018,7 +2052,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  cupsUIResolver %s does not list at least "
-                         "two different options!\n"),
+                         "two different options\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -2035,7 +2069,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        _cupsLangPrintf(stdout,
-                       _("      %s  cupsUIResolver %s causes a loop!\n"),
+                       _("      %s  cupsUIResolver %s causes a loop\n"),
                        prefix, constattr->spec);
 
        if (!warn)
@@ -2072,7 +2106,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing option %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option1,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2086,7 +2120,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing choice *%s %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option1, c->choice1,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2113,7 +2147,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing option %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option2,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2127,7 +2161,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  Missing choice *%s %s in "
-                         "UIConstraints \"*%s %s *%s %s\"!\n"),
+                         "UIConstraints \"*%s %s *%s %s\"\n"),
                        prefix, c->option2, c->choice2,
                        c->option1, c->choice1, c->option2, c->choice2);
 
@@ -2174,7 +2208,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      **FAIL**  Group names %s and %s differ only "
-                           "by case!\n"),
+                           "by case\n"),
                          groupa->name, groupb->name);
 
        errors ++;
@@ -2196,7 +2230,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      **FAIL**  Option names %s and %s differ only "
-                           "by case!\n"),
+                           "by case\n"),
                          optiona->keyword, optionb->keyword);
 
        errors ++;
@@ -2219,7 +2253,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      **FAIL**  Multiple occurrences of %s "
-                             "choice name %s!\n"),
+                             "choice name %s\n"),
                            optiona->keyword, choicea->choice);
 
          errors ++;
@@ -2236,7 +2270,7 @@ check_case(ppd_file_t *ppd,               /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      **FAIL**  %s choice names %s and %s "
-                             "differ only by case!\n"),
+                             "differ only by case\n"),
                            optiona->keyword, choicea->choice, choiceb->choice);
 
          errors ++;
@@ -2304,7 +2338,7 @@ check_defaults(ppd_file_t *ppd,           /* I - PPD file */
 
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
-                           _("      %s  %s %s does not exist!\n"),
+                           _("      %s  %s %s does not exist\n"),
                            prefix, attr->name, attr->value);
 
           if (!warn)
@@ -2351,7 +2385,7 @@ check_duplex(ppd_file_t *ppd,             /* I - PPD file */
 
        _cupsLangPrintf(stdout,
                        _("      %s  REQUIRED %s does not define "
-                         "choice None!\n"
+                         "choice None\n"
                          "                REF: Page 122, section 5.17\n"),
                        prefix, option->keyword);
       }
@@ -2374,7 +2408,7 @@ check_duplex(ppd_file_t *ppd,             /* I - PPD file */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPrintf(stdout,
-                         _("      %s  Bad %s choice %s!\n"
+                         _("      %s  Bad %s choice %s\n"
                            "                REF: Page 122, section 5.17\n"),
                          prefix, option->keyword, choice->choice);
        }
@@ -2408,6 +2442,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
                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**";
@@ -2426,7 +2461,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsFilter value \"%s\"!\n"),
+                       _("      %s  Bad cupsFilter value \"%s\"\n"),
                        prefix, ppd->filters[i]);
 
       if (!warn)
@@ -2449,14 +2484,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
                   program);
       }
 
-      if (access(pathprog, X_OK))
+      if (stat(pathprog, &fileinfo))
       {
        if (!warn && !errors && !verbose)
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        if (verbose >= 0)
          _cupsLangPrintf(stdout, _("      %s  Missing cupsFilter "
-                                   "file \"%s\"\n"), prefix, program);
+                                   "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 ++;
@@ -2474,6 +2523,20 @@ check_filters(ppd_file_t *ppd,           /* I - PPD file */
        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)
@@ -2483,7 +2546,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsPreFilter value \"%s\"!\n"),
+                       _("      %s  Bad cupsPreFilter value \"%s\"\n"),
                        prefix, attr->value ? attr->value : "");
 
       if (!warn)
@@ -2506,18 +2569,33 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
                   program);
       }
 
-      if (access(pathprog, X_OK))
+      if (stat(pathprog, &fileinfo))
       {
        if (!warn && !errors && !verbose)
          _cupsLangPuts(stdout, _(" FAIL\n"));
 
        if (verbose >= 0)
          _cupsLangPrintf(stdout, _("      %s  Missing cupsPreFilter "
-                                   "file \"%s\"\n"), prefix, program);
+                                   "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);
     }
@@ -2532,7 +2610,24 @@ check_filters(ppd_file_t *ppd,           /* I - PPD file */
        attr != NULL; 
        attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
   {
-    if (!attr->value || access(attr->value, 0))
+    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"));
@@ -2540,13 +2635,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APDialogExtension file \"%s\"\n"),
-                       prefix, attr->value ? attr->value : "<NULL>");
+                       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", attr->value, errors, verbose,
+      errors = valid_path("APDialogExtension", pathprog, errors, verbose,
                           warn);
   }
 
@@ -2556,7 +2666,24 @@ check_filters(ppd_file_t *ppd,           /* I - PPD file */
 
   if ((attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
   {
-    if (!attr->value || access(attr->value, 0))
+    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"));
@@ -2564,13 +2691,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APPrinterIconPath file \"%s\"\n"),
-                       prefix, attr->value ? attr->value : "<NULL>");
+                       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", attr->value, errors, verbose,
+      errors = valid_path("APPrinterIconPath", pathprog, errors, verbose,
                           warn);
   }
 
@@ -2580,7 +2722,24 @@ check_filters(ppd_file_t *ppd,           /* I - PPD file */
 
   if ((attr = ppdFindAttr(ppd, "APPrinterLowInkTool", NULL)) != NULL)
   {
-    if (!attr->value || access(attr->value, 0))
+    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"));
@@ -2588,13 +2747,28 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APPrinterLowInkTool file \"%s\"\n"),
-                       prefix, attr->value ? attr->value : "<NULL>");
+                       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", attr->value, errors, verbose,
+      errors = valid_path("APPrinterLowInkTool", pathprog, errors, verbose,
                           warn);
   }
 
@@ -2604,7 +2778,24 @@ check_filters(ppd_file_t *ppd,           /* I - PPD file */
 
   if ((attr = ppdFindAttr(ppd, "APPrinterUtilityPath", NULL)) != NULL)
   {
-    if (!attr->value || access(attr->value, 0))
+    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"));
@@ -2612,14 +2803,96 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing "
                                  "APPrinterUtilityPath file \"%s\"\n"),
+                       prefix, pathprog);
+
+      if (!warn)
+       errors ++;
+    }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "APPrinterUtilityPath file \"%s\"\n"), prefix,
+                       pathprog);
+
+      if (!warn)
+       errors ++;
+    }
+    else
+      errors = valid_path("APPrinterUtilityPath", pathprog, errors, verbose,
+                          warn);
+  }
+
+ /*
+  * APScanAppBundleID and APScanAppPath
+  */
+
+  if ((attr = ppdFindAttr(ppd, "APScanAppPath", NULL)) != NULL)
+  {
+    if (strcmp(attr->name, "APScanAppPath"))
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout,
+                       _("      %s  Bad spelling of %s - should be %s\n"),
+                       prefix, attr->name, "APScanAppPath");
+
+      if (!warn)
+        errors ++;
+    }
+
+    if (!attr->value || stat(attr->value, &fileinfo))
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Missing "
+                                 "APScanAppPath file \"%s\"\n"),
                        prefix, attr->value ? attr->value : "<NULL>");
 
       if (!warn)
        errors ++;
     }
+    else if (fileinfo.st_uid != 0 ||
+            (fileinfo.st_mode & MODE_WRITE) ||
+            (fileinfo.st_mode & MODE_MASK) != MODE_DIRECTORY)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout, _("      %s  Bad permissions on "
+                                 "APScanAppPath file \"%s\"\n"), prefix,
+                       attr->value);
+
+      if (!warn)
+       errors ++;
+    }
     else
-      errors = valid_path("APPrinterUtilityPath", attr->value, errors, verbose,
+      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__ */
 
@@ -2643,6 +2916,7 @@ check_profiles(ppd_file_t *ppd,           /* I - PPD file */
   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 */
@@ -2669,7 +2943,7 @@ check_profiles(ppd_file_t *ppd,           /* I - PPD file */
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
-                       _("      %s  Bad cupsICCProfile %s!\n"),
+                       _("      %s  Bad cupsICCProfile %s\n"),
                        prefix, attr->spec);
 
       if (!warn)
@@ -2697,14 +2971,29 @@ check_profiles(ppd_file_t *ppd,         /* I - PPD file */
                 attr->value);
     }
 
-    if (access(filename, 0))
+    if (stat(filename, &fileinfo))
     {
       if (!warn && !errors && !verbose)
        _cupsLangPuts(stdout, _(" FAIL\n"));
 
       if (verbose >= 0)
        _cupsLangPrintf(stdout, _("      %s  Missing cupsICCProfile "
-                                 "file \"%s\"!\n"), prefix, attr->value);
+                                 "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 ++;
@@ -2732,7 +3021,7 @@ check_profiles(ppd_file_t *ppd,           /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      %s  cupsICCProfile %s hash value "
-                           "collides with %s!\n"), prefix, attr->spec,
+                           "collides with %s\n"), prefix, attr->spec,
                          specs[i]);
 
        if (!warn)
@@ -2786,7 +3075,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
 
     if (verbose >= 0)
       _cupsLangPrintf(stdout,
-                     _("      %s  Missing REQUIRED PageSize option!\n"
+                     _("      %s  Missing REQUIRED PageSize option\n"
                        "                REF: Page 99, section 5.14.\n"),
                      prefix);
 
@@ -2801,7 +3090,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
 
     if (verbose >= 0)
       _cupsLangPrintf(stdout,
-                     _("      %s  Missing REQUIRED PageRegion option!\n"
+                     _("      %s  Missing REQUIRED PageRegion option\n"
                        "                REF: Page 100, section 5.14.\n"),
                      prefix);
 
@@ -2840,7 +3129,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      %s  Size \"%s\" has unexpected dimensions "
-                           "(%gx%g)!\n"),
+                           "(%gx%g)\n"),
                          prefix, size->name, size->width, size->length);
 
        if (!warn)
@@ -2864,7 +3153,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
                   (int (*)(const void *, const void *))strcmp))
       {
        _cupsLangPrintf(stdout,
-                       _("      %s  Non-standard size name \"%s\"!\n"
+                       _("      %s  Non-standard size name \"%s\"\n"
                          "                REF: Page 187, section B.2.\n"),
                        prefix, size->name);
       }
@@ -2882,7 +3171,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
                        _("      %s  Size \"%s\" defined for %s but not for "
-                         "%s!\n"),
+                         "%s\n"),
                        prefix, size->name, "PageRegion", "PageSize");
 
       if (!warn)
@@ -2896,7 +3185,7 @@ check_sizes(ppd_file_t *ppd,              /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
                        _("      %s  Size \"%s\" defined for %s but not for "
-                         "%s!\n"),
+                         "%s\n"),
                        prefix, size->name, "PageSize", "PageRegion");
 
       if (!warn)
@@ -2948,7 +3237,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
          language;
         language = (char *)cupsArrayNext(languages))
     {
-      langlen = strlen(language);
+      langlen = (int)strlen(language);
       if (langlen != 2 && langlen != 5)
       {
        if (!warn && !errors && !verbose)
@@ -2956,7 +3245,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
 
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
-                         _("      %s  Bad language \"%s\"!\n"),
+                         _("      %s  Bad language \"%s\"\n"),
                          prefix, language);
 
        if (!warn)
@@ -2993,7 +3282,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
          if (verbose >= 0)
            _cupsLangPrintf(stdout,
                            _("      %s  Missing \"%s\" translation "
-                             "string for option %s!\n"),
+                             "string for option %s\n"),
                            prefix, language, option->keyword);
 
           if (!warn)
@@ -3007,7 +3296,7 @@ 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"),
+                             "string for option %s\n"),
                            prefix, language, option->keyword);
 
          if (!warn)
@@ -3054,7 +3343,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                _cupsLangPrintf(stdout,
                                _("      %s  Bad UTF-8 \"%s\" "
                                  "translation string for option %s, "
-                                 "choice %s!\n"),
+                                 "choice %s\n"),
                                prefix, language,
                                ckeyword + 1 + strlen(language),
                                "True");
@@ -3086,7 +3375,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                    _cupsLangPrintf(stdout,
                                    _("      %s  Missing \"%s\" "
                                      "translation string for option %s, "
-                                     "choice %s!\n"),
+                                     "choice %s\n"),
                                    prefix, language,
                                    ckeyword + 1 + strlen(language),
                                    cparam->name);
@@ -3103,7 +3392,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                    _cupsLangPrintf(stdout,
                                    _("      %s  Bad UTF-8 \"%s\" "
                                      "translation string for option %s, "
-                                     "choice %s!\n"),
+                                     "choice %s\n"),
                                    prefix, language,
                                    ckeyword + 1 + strlen(language),
                                    cparam->name);
@@ -3126,7 +3415,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
              _cupsLangPrintf(stdout,
                              _("      %s  Missing \"%s\" "
                                "translation string for option %s, "
-                               "choice %s!\n"),
+                               "choice %s\n"),
                              prefix, language, option->keyword,
                              option->choices[j].choice);
 
@@ -3142,7 +3431,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
              _cupsLangPrintf(stdout,
                              _("      %s  Bad UTF-8 \"%s\" "
                                "translation string for option %s, "
-                               "choice %s!\n"),
+                               "choice %s\n"),
                              prefix, language, option->keyword,
                              option->choices[j].choice);
 
@@ -3179,7 +3468,7 @@ 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 ++;
@@ -3364,6 +3653,8 @@ 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,duplex,filters,"
                  "profiles,sizes,translations}\n"
@@ -3447,7 +3738,7 @@ valid_path(const char *keyword,           /* I - Keyword using path */
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
                        _("      %s  %s file \"%s\" has the wrong "
-                         "capitalization!\n"), prefix, keyword, path);
+                         "capitalization\n"), prefix, keyword, path);
 
       if (!warn)
        errors ++;