]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - systemv/cupstestppd.c
Merge changes from CUPS 1.4svn-r7715.
[thirdparty/cups.git] / systemv / cupstestppd.c
index 54b3b4c620e20607519a852d51113ffa7f4df052..b2317564956ccae7c3a377628b322152731fd6d1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$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.
@@ -36,6 +38,7 @@
 
 #include <cups/string.h>
 #include <cups/cups.h>
+#include <cups/ppd-private.h>
 #include <cups/i18n.h>
 #include <cups/raster.h>
 #include <errno.h>
@@ -53,8 +56,9 @@ enum
   WARN_CONSTRAINTS = 1,
   WARN_DEFAULTS = 2,
   WARN_FILTERS = 4,
-  WARN_TRANSLATIONS = 8,
-  WARN_ALL = 15
+  WARN_PROFILES = 8,
+  WARN_TRANSLATIONS = 16,
+  WARN_ALL = 31
 };
 
 
@@ -96,6 +100,8 @@ static int   check_defaults(ppd_file_t *ppd, int errors, int verbose,
                               int warn);
 static int     check_filters(ppd_file_t *ppd, const char *root, int errors,
                              int verbose, int warn);
+static int     check_profiles(ppd_file_t *ppd, const char *root, int errors,
+                              int verbose, int warn);
 static int     check_translations(ppd_file_t *ppd, int errors, int verbose,\
                                   int warn);
 static void    show_conflicts(ppd_file_t *ppd);
@@ -124,9 +130,7 @@ main(int  argc,                             /* I - Number of command-line args */
   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 */
@@ -137,12 +141,14 @@ main(int  argc,                           /* I - Number of command-line args */
   ppd_group_t  *group2;                /* UI group */
   ppd_option_t *option2;               /* Standard UI option */
   ppd_choice_t *choice;                /* Standard UI option choice */
+  struct lconv *loc;                   /* Locale data */
   static char  *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
   static char  *sections[] = { "ANY", "DOCUMENT", "EXIT",
                                 "JCL", "PAGE", "PROLOG" };
 
 
   _cupsSetLocale(argv);
+  loc = localeconv();
 
  /*
   * Display PPD files for each file listed on the command-line...
@@ -186,6 +192,8 @@ main(int  argc,                             /* I - Number of command-line args */
                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"))
@@ -244,10 +252,10 @@ main(int  argc,                           /* I - Number of command-line args */
         * Read from stdin...
        */
 
-        if (verbose >= 0)
-          printf("(stdin):");
-
         ppd = ppdOpen(stdin);
+
+        if (verbose >= 0)
+          printf("%s:", (ppd && ppd->pcfilename) ? ppd->pcfilename : "(stdin)");
       }
       else
       {
@@ -364,7 +372,7 @@ main(int  argc,                             /* I - Number of command-line args */
 
       if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL &&
           attr->value)
-        ppdversion = (int)(10 * atof(attr->value) + 0.5);
+        ppdversion = (int)(10 * _cupsStrScand(attr->value, NULL, loc) + 0.5);
 
       for (j = 0; j < ppd->num_filters; j ++)
         if (strstr(ppd->filters[j], "application/vnd.cups-raster"))
@@ -1072,6 +1080,9 @@ main(int  argc,                           /* I - Number of command-line args */
       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);
 
@@ -1197,6 +1208,9 @@ main(int  argc,                           /* I - Number of command-line args */
        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);
 
@@ -1360,43 +1374,6 @@ main(int  argc,                          /* I - Number of command-line args */
          }
       }
 
-     /*
-      * cupsICCProfile
-      */
-
-      for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); 
-          attr != NULL; 
-          attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
-      {
-       if (attr->value)
-       {
-         if (attr->value[0] == '/')
-           snprintf(pathprog, sizeof(pathprog), "%s%s", root, attr->value);
-         else
-         {
-           if ((ptr = getenv("CUPS_DATADIR")) == NULL)
-             ptr = CUPS_DATADIR;
-
-            if (*ptr == '/' || !*root)
-             snprintf(pathprog, sizeof(pathprog), "%s%s/profiles/%s", root,
-                      ptr, attr->value);
-            else
-             snprintf(pathprog, sizeof(pathprog), "%s/%s/profiles/%s", root,
-                      ptr, attr->value);
-          }
-       }
-
-       if (!attr->value || !attr->value[0] || stat(pathprog, &statbuf))
-       {
-         if (verbose >= 0)
-           _cupsLangPrintf(stdout,
-                           _("        WARN    Missing cupsICCProfile "
-                             "file \"%s\"\n"),
-                           !attr->value || !attr->value[0] ? "<NULL>" :
-                                                             attr->value);
-       }
-      }
-
 #ifdef __APPLE__
      /*
       * APDialogExtension
@@ -1406,7 +1383,7 @@ main(int  argc,                           /* I - Number of command-line args */
           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>");
@@ -1420,7 +1397,7 @@ main(int  argc,                           /* I - Number of command-line args */
           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>");
@@ -1651,12 +1628,12 @@ check_basics(const char *filename)      /* I - PPD file to check */
 
           if (eol == EOL_NONE)
            eol = EOL_CRLF;
-         else
+         else if (eol != EOL_CRLF)
            mixed = 1;
        }
        else if (eol == EOL_NONE)
          eol = EOL_CR;
-        else
+        else if (eol != EOL_CR)
          mixed = 1;
       }
       
@@ -1854,12 +1831,12 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
              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 */
@@ -1867,13 +1844,10 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
 
   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"));
@@ -1881,7 +1855,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
       if (verbose >= 0)
        _cupsLangPrintf(stdout,
                        _("      %s  Bad cupsFilter value \"%s\"!\n"),
-                       prefix, attr->value ? attr->value : "");
+                       prefix, ppd->filters[i]);
 
       if (!warn)
         errors ++;
@@ -1903,7 +1877,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
                   program);
       }
 
-      if (stat(pathprog, &statbuf))
+      if (access(pathprog, X_OK))
       {
        if (!warn && !errors && !verbose)
          _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -1923,8 +1897,8 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
        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"));
@@ -1954,7 +1928,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
                   program);
       }
 
-      if (stat(pathprog, &statbuf))
+      if (access(pathprog, X_OK))
       {
        if (!warn && !errors && !verbose)
          _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -1973,6 +1947,133 @@ check_filters(ppd_file_t *ppd,          /* I - PPD file */
 }
 
 
+/*
+ * '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.
  */
@@ -1985,9 +2086,9 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
 {
   int          j;                      /* Looping var */
   ppd_attr_t   *attr;                  /* PPD attribute */
-  char         *languages,             /* Copy of attribute value */
-               *langstart,             /* Start of current language */
-               *langptr,               /* Pointer into languages */
+  cups_array_t *languages;             /* Array of languages */
+  int          langlen;                /* Length of language */
+  char         *language,              /* Current language */
                keyword[PPD_MAX_NAME],  /* Localization keyword (full) */
                llkeyword[PPD_MAX_NAME],/* Localization keyword (base) */
                ckeyword[PPD_MAX_NAME], /* Custom option keyword (full) */
@@ -1996,50 +2097,24 @@ check_translations(ppd_file_t *ppd,     /* I - PPD file */
   ppd_option_t *option;                /* Standard UI option */
   ppd_coption_t        *coption;               /* Custom option */
   ppd_cparam_t *cparam;                /* Custom parameter */
-  cups_array_t *langlist;              /* List of languages so far */
   char         ll[3];                  /* Base language */
   const char   *prefix;                /* WARN/FAIL prefix */
 
 
   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"));
@@ -2047,7 +2122,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
        if (verbose >= 0)
          _cupsLangPrintf(stdout,
                          _("      %s  Bad language \"%s\"!\n"),
-                         prefix, langstart);
+                         prefix, language);
 
        if (!warn)
          errors ++;
@@ -2055,12 +2130,10 @@ check_translations(ppd_file_t *ppd,     /* I - PPD file */
        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...
@@ -2073,7 +2146,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
         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 &&
@@ -2086,7 +2159,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
            _cupsLangPrintf(stdout,
                            _("      %s  Missing \"%s\" translation "
                              "string for option %s!\n"),
-                           prefix, langstart, option->keyword);
+                           prefix, language, option->keyword);
 
           if (!warn)
            errors ++;
@@ -2100,13 +2173,13 @@ check_translations(ppd_file_t *ppd,     /* I - PPD file */
            _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);
@@ -2118,7 +2191,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                                             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))
@@ -2131,8 +2204,8 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                                _("      %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)
@@ -2146,7 +2219,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                   cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
              {
                snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
-                        langstart, option->keyword);
+                        language, option->keyword);
                snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s",
                         ll, option->keyword);
 
@@ -2163,8 +2236,8 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                                    _("      %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)
@@ -2180,8 +2253,8 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                                    _("      %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)
@@ -2203,7 +2276,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                              _("      %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)
@@ -2219,7 +2292,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
                              _("      %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)
@@ -2233,20 +2306,20 @@ check_translations(ppd_file_t *ppd,     /* I - PPD file */
     * Verify that we have the base language for each localized one...
     */
 
-    for (langptr = (char *)cupsArrayFirst(langlist);
-        langptr;
-        langptr = (char *)cupsArrayNext(langlist))
-      if (langptr[2])
+    for (language = (char *)cupsArrayFirst(languages);
+        language;
+        language = (char *)cupsArrayNext(languages))
+      if (language[2])
       {
        /*
        * Lookup the base language...
        */
 
-       cupsArraySave(langlist);
+       cupsArraySave(languages);
 
-       strlcpy(ll, langptr, sizeof(ll));
+       strlcpy(ll, language, sizeof(ll));
 
-       if (!cupsArrayFind(langlist, ll) && strcmp(ll, "zh"))
+       if (!cupsArrayFind(languages, ll) && strcmp(ll, "zh"))
        {
          if (!warn && !errors && !verbose)
            _cupsLangPuts(stdout, _(" FAIL\n"));
@@ -2260,15 +2333,14 @@ check_translations(ppd_file_t *ppd,     /* I - PPD file */
            errors ++;
        }
 
-       cupsArrayRestore(langlist);
+       cupsArrayRestore(languages);
       }
 
    /*
     * Free memory used for the languages...
     */
 
-    cupsArrayDelete(langlist);
-    free(languages);
+    _ppdFreeLanguages(languages);
   }
 
   return (errors);
@@ -2529,5 +2601,5 @@ valid_utf8(const char *s)         /* I - String to check */
 
 
 /*
- * 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 $".
  */