]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/conflicts.c
<rdar://problem/13655599> Seed: Print queue JOBS disappear after computer Wakes up...
[thirdparty/cups.git] / cups / conflicts.c
index 042bfdcec6f74bc87fa0bbc3f00ea7d280f4f5c9..ae048d135e8ed44b296793eb7a2c7045cf0b9fdf 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id$"
  *
- *   Option marking routines for the Common UNIX Printing System (CUPS).
+ *   Option marking routines for CUPS.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2012 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *
  * Contents:
  *
+ *   cupsGetConflicts()       - Get a list of conflicting options in a marked
+ *                              PPD.
+ *   cupsResolveConflicts()   - Resolve conflicts in a marked PPD.
  *   ppdConflicts()           - Check to see if there are any conflicts among
  *                              the marked option choices.
  *   ppdInstallableConflict() - Test whether an option choice conflicts with an
  *                              installable option.
- *   cupsResolveConflicts()   - Resolve conflicts in a marked PPD.
  *   ppd_is_installable()     - Determine whether an option is in the
  *                              InstallableOptions group.
  *   ppd_load_constraints()   - Load constraints from a PPD file.
@@ -33,9 +35,8 @@
  * Include necessary headers...
  */
 
+#include "cups-private.h"
 #include "ppd-private.h"
-#include "string.h"
-#include "debug.h"
 
 
 /*
@@ -45,6 +46,7 @@
 enum
 {
   _PPD_NORMAL_CONSTRAINTS,
+  _PPD_OPTION_CONSTRAINTS,
   _PPD_INSTALLABLE_CONSTRAINTS,
   _PPD_ALL_CONSTRAINTS
 };
@@ -57,110 +59,88 @@ enum
 static int             ppd_is_installable(ppd_group_t *installable,
                                           const char *option);
 static void            ppd_load_constraints(ppd_file_t *ppd);
-static cups_array_t    *ppd_test_constraints(ppd_file_t *ppd, int num_options,
+static cups_array_t    *ppd_test_constraints(ppd_file_t *ppd,
+                                             const char *option,
+                                             const char *choice,
+                                             int num_options,
                                              cups_option_t *options,
                                              int which);
 
 
 /*
- * 'ppdConflicts()' - Check to see if there are any conflicts among the
- *                    marked option choices.
+ * 'cupsGetConflicts()' - Get a list of conflicting options in a marked PPD.
  *
- * The returned value is the same as returned by @link ppdMarkOption@.
+ * This function gets a list of options that would conflict if "option" and
+ * "choice" were marked in the PPD.  You would typically call this function
+ * after marking the currently selected options in the PPD in order to
+ * determine whether a new option selection would cause a conflict.
+ *
+ * The number of conflicting options are returned with "options" pointing to
+ * the conflicting options.  The returned option array must be freed using
+ * @link cupsFreeOptions@.
+ *
+ * @since CUPS 1.4/OS X 10.6@
  */
 
-int                                    /* O - Number of conflicts found */
-ppdConflicts(ppd_file_t *ppd)          /* I - PPD to check */
+int                                    /* O - Number of conflicting options */
+cupsGetConflicts(
+    ppd_file_t    *ppd,                        /* I - PPD file */
+    const char    *option,             /* I - Option to test */
+    const char    *choice,             /* I - Choice to test */
+    cups_option_t **options)           /* O - Conflicting options */
 {
-  int                  i,              /* Looping variable */
-                       conflicts;      /* Number of conflicts */
+  int                  i,              /* Looping var */
+                       num_options;    /* Number of conflicting options */
   cups_array_t         *active;        /* Active conflicts */
   _ppd_cups_uiconsts_t *c;             /* Current constraints */
   _ppd_cups_uiconst_t  *cptr;          /* Current constraint */
-  ppd_option_t *o;                     /* Current option */
+  ppd_choice_t         *marked;        /* Marked choice */
 
 
-  if (!ppd)
-    return (0);
-
  /*
-  * Clear all conflicts...
+  * Range check input...
   */
 
-  for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
-    o->conflicted = 0;
+  if (options)
+    *options = NULL;
+
+  if (!ppd || !option || !choice || !options)
+    return (0);
 
  /*
   * Test for conflicts...
   */
 
-  active    = ppd_test_constraints(ppd, 0, NULL, _PPD_ALL_CONSTRAINTS);
-  conflicts = cupsArrayCount(active);
+  active = ppd_test_constraints(ppd, option, choice, 0, NULL,
+                                _PPD_ALL_CONSTRAINTS);
 
  /*
-  * Loop through all of the UI constraints and flag any options
-  * that conflict...
+  * Loop through all of the UI constraints and add any options that conflict...
   */
 
-  for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
+  for (num_options = 0, c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
        c;
        c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
   {
     for (i = c->num_constraints, cptr = c->constraints;
          i > 0;
         i --, cptr ++)
-      cptr->option->conflicted = 1;
+      if (_cups_strcasecmp(cptr->option->keyword, option))
+      {
+        if (cptr->choice)
+         num_options = cupsAddOption(cptr->option->keyword,
+                                     cptr->choice->choice, num_options,
+                                     options);
+        else if ((marked = ppdFindMarkedChoice(ppd,
+                                              cptr->option->keyword)) != NULL)
+         num_options = cupsAddOption(cptr->option->keyword, marked->choice,
+                                     num_options, options);
+      }
   }
 
   cupsArrayDelete(active);
 
- /*
-  * Return the number of conflicts found...
-  */
-
-  return (conflicts);
-}
-
-
-/*
- * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
- *                              an installable option.
- *
- * This function tests whether a particular option choice is available based
- * on constraints against options in the "InstallableOptions" group.
- *
- * @since CUPS 1.4@
- */
-
-int                                    /* O - 1 if conflicting, 0 if not conflicting */
-ppdInstallableConflict(
-    ppd_file_t *ppd,                   /* I - PPD file */
-    const char *option,                        /* I - Option */
-    const char *choice)                        /* I - Choice */
-{
-  cups_array_t *active;                /* Active conflicts */
-  cups_option_t        test;                   /* Test against this option */
-
-
- /* 
-  * Range check input...
-  */
-
-  if (!ppd || !option || !choice)
-    return (0);
-
- /*
-  * Test constraints using the new option...
-  */
-
-  test.name  = (char *)option;
-  test.value = (char *)choice;
-  active     = ppd_test_constraints(ppd, 1, &test,
-                                    _PPD_INSTALLABLE_CONSTRAINTS);
-
-  cupsArrayDelete(active);
-
-  return (active != NULL);
+  return (num_options);
 }
 
 
@@ -168,30 +148,37 @@ ppdInstallableConflict(
  * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD.
  *
  * This function attempts to resolve any conflicts in a marked PPD, returning
- * a list of option changes that are required to resolve any conflicts.  On
- * input, "num_options" and "options" contain any pending option changes that
- * have not yet been marked, while "option" and "choice" contain the most recent
+ * a list of option changes that are required to resolve them.  On input,
+ * "num_options" and "options" contain any pending option changes that have
+ * not yet been marked, while "option" and "choice" contain the most recent
  * selection which may or may not be in "num_options" or "options".
  *
  * On successful return, "num_options" and "options" are updated to contain
  * "option" and "choice" along with any changes required to resolve conflicts
- * specified in the PPD file.  If option conflicts cannot be resolved,
- * "num_options" and "options" are not changed.
+ * specified in the PPD file and 1 is returned.
+ *
+ * If option conflicts cannot be resolved, "num_options" and "options" are not
+ * changed and 0 is returned.
  *
- * @code ppdResolveConflicts@ uses one of two sources of option constraint
- * information.  The preferred constraint information is defined by
+ * When resolving conflicts, @code cupsResolveConflicts@ does not consider
+ * changes to the current page size (@code media@, @code PageSize@, and
+ * @code PageRegion@) or to the most recent option specified in "option".
+ * Thus, if the only way to resolve a conflict is to change the page size
+ * or the option the user most recently changed, @code cupsResolveConflicts@
+ * will return 0 to indicate it was unable to resolve the conflicts.
+ *
+ * The @code cupsResolveConflicts@ function uses one of two sources of option
+ * constraint information.  The preferred constraint information is defined by
  * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this
- * case, the PPD file provides constraint resolution actions.  In this case,
- * it should not be possible for @ppdResolveConflicts@ to fail, however it
- * will do so if a resolver loop is detected.
+ * case, the PPD file provides constraint resolution actions.
  *
- * The backup constraint infomration is defined by the
+ * The backup constraint information is defined by the
  * @code UIConstraints@ and @code NonUIConstraints@ attributes.  These
- * constraints are resolved algorithmically by selecting the default choice
- * for the conflicting option.  Unfortunately, this method is far more likely
- * to fail.
+ * constraints are resolved algorithmically by first selecting the default
+ * choice for the conflicting option, then iterating over all possible choices
+ * until a non-conflicting option choice is found.
  *
- * @since CUPS 1.4@
+ * @since CUPS 1.4/OS X 10.6@
  */
 
 int                                    /* O  - 1 on success, 0 on failure */
@@ -203,18 +190,26 @@ cupsResolveConflicts(
     cups_option_t **options)           /* IO - Additional selected options */
 {
   int                  i,              /* Looping var */
+                       tries,          /* Number of tries */
                        num_newopts;    /* Number of new options */
   cups_option_t                *newopts;       /* New options */
   cups_array_t         *active,        /* Active constraints */
                        *pass,          /* Resolvers for this pass */
-                       *resolvers;     /* Resolvers we have used */
+                       *resolvers,     /* Resolvers we have used */
+                       *test;          /* Test array for conflicts */
   _ppd_cups_uiconsts_t *consts;        /* Current constraints */
   _ppd_cups_uiconst_t  *constptr;      /* Current constraint */
   ppd_attr_t           *resolver;      /* Current resolver */
+  const char           *resval;        /* Pointer into resolver value */
+  char                 resoption[PPD_MAX_NAME],
+                                       /* Current resolver option */
+                       reschoice[PPD_MAX_NAME],
+                                       /* Current resolver choice */
+                       *resptr,        /* Pointer into option/choice */
+                       firstpage[255]; /* AP_FIRSTPAGE_Keyword string */
   const char           *value;         /* Selected option value */
   int                  changed;        /* Did we change anything? */
   ppd_choice_t         *marked;        /* Marked choice */
-  ppd_option_t         *ignored;       /* Ignored option */
 
 
  /*
@@ -234,7 +229,7 @@ cupsResolveConflicts(
   for (i = 0; i < *num_options; i ++)
     num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value,
                                 num_newopts, &newopts);
-  if (option)
+  if (option && _cups_strcasecmp(option, "Collate"))
     num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
 
  /*
@@ -244,13 +239,17 @@ cupsResolveConflicts(
   cupsArraySave(ppd->sorted_attrs);
 
   resolvers = NULL;
-  pass      = cupsArrayNew((cups_array_func_t)strcasecmp, NULL);
+  pass      = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
+  tries     = 0;
 
-  while ((active = ppd_test_constraints(ppd, num_newopts, newopts,
+  while (tries < 100 &&
+         (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts,
                                         _PPD_ALL_CONSTRAINTS)) != NULL)
   {
+    tries ++;
+
     if (!resolvers)
-      resolvers = cupsArrayNew((cups_array_func_t)strcasecmp, NULL);
+      resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
 
     for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0;
          consts;
@@ -271,7 +270,7 @@ cupsResolveConflicts(
          * Resolver loop!
          */
 
-         DEBUG_printf(("ppdResolveConflicts: Resolver loop with %s!\n",
+         DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!",
                        consts->resolver));
           goto error;
        }
@@ -279,14 +278,14 @@ cupsResolveConflicts(
         if ((resolver = ppdFindAttr(ppd, "cupsUIResolver",
                                    consts->resolver)) == NULL)
         {
-         DEBUG_printf(("ppdResolveConflicts: Resolver %s not found!\n",
+         DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!",
                        consts->resolver));
          goto error;
        }
 
         if (!resolver->value)
        {
-         DEBUG_printf(("ppdResolveConflicts: Resolver %s has no value!\n",
+         DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!",
                        consts->resolver));
          goto error;
        }
@@ -298,101 +297,265 @@ cupsResolveConflicts(
         cupsArrayAdd(pass, consts->resolver);
        cupsArrayAdd(resolvers, consts->resolver);
 
-        num_newopts = _ppdParseOptions(resolver->value, num_newopts, &newopts);
-       changed     = 1;
+        for (resval = resolver->value; *resval && !changed;)
+       {
+         while (_cups_isspace(*resval))
+           resval ++;
+
+         if (*resval != '*')
+           break;
+
+         for (resval ++, resptr = resoption;
+              *resval && !_cups_isspace(*resval);
+              resval ++)
+            if (resptr < (resoption + sizeof(resoption) - 1))
+             *resptr++ = *resval;
+
+          *resptr = '\0';
+
+         while (_cups_isspace(*resval))
+           resval ++;
+
+         for (resptr = reschoice;
+              *resval && !_cups_isspace(*resval);
+              resval ++)
+            if (resptr < (reschoice + sizeof(reschoice) - 1))
+             *resptr++ = *resval;
+
+          *resptr = '\0';
+
+          if (!resoption[0] || !reschoice[0])
+           break;
+
+         /*
+         * Is this the option we are changing?
+         */
+
+          snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption);
+
+         if (option &&
+             (!_cups_strcasecmp(resoption, option) ||
+              !_cups_strcasecmp(firstpage, option) ||
+              (!_cups_strcasecmp(option, "PageSize") &&
+               !_cups_strcasecmp(resoption, "PageRegion")) ||
+              (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") &&
+               !_cups_strcasecmp(resoption, "PageSize")) ||
+              (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") &&
+               !_cups_strcasecmp(resoption, "PageRegion")) ||
+              (!_cups_strcasecmp(option, "PageRegion") &&
+               !_cups_strcasecmp(resoption, "PageSize")) ||
+              (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") &&
+               !_cups_strcasecmp(resoption, "PageSize")) ||
+              (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") &&
+               !_cups_strcasecmp(resoption, "PageRegion"))))
+           continue;
+
+        /*
+         * Try this choice...
+         */
+
+          if ((test = ppd_test_constraints(ppd, resoption, reschoice,
+                                          num_newopts, newopts,
+                                          _PPD_ALL_CONSTRAINTS)) == NULL)
+         {
+          /*
+           * That worked...
+           */
+
+            changed = 1;
+         }
+         else
+            cupsArrayDelete(test);
+
+        /*
+         * Add the option/choice from the resolver regardless of whether it
+         * worked; this makes sure that we can cascade several changes to
+         * make things resolve...
+         */
+
+         num_newopts = cupsAddOption(resoption, reschoice, num_newopts,
+                                     &newopts);
+        }
       }
       else
       {
        /*
         * Try resolving by choosing the default values for non-installable
-       * options...
+       * options, then by iterating through the possible choices...
        */
 
-        for (i = consts->num_constraints, constptr = consts->constraints,
-                ignored = NULL;
-            i > 0;
+        int            j;              /* Looping var */
+       ppd_choice_t    *cptr;          /* Current choice */
+        ppd_size_t     *size;          /* Current page size */
+
+
+        for (i = consts->num_constraints, constptr = consts->constraints;
+            i > 0 && !changed;
             i --, constptr ++)
        {
-         if (constptr->installable ||
-             !strcasecmp(constptr->option->keyword, "PageSize") ||
-             !strcasecmp(constptr->option->keyword, "PageRegion"))
+        /*
+         * Can't resolve by changing an installable option...
+         */
+
+         if (constptr->installable)
            continue;
 
-         if (option && !strcasecmp(constptr->option->keyword, option))
-         {
-           ignored = constptr->option;
+         /*
+         * Is this the option we are changing?
+         */
+
+         if (option &&
+             (!_cups_strcasecmp(constptr->option->keyword, option) ||
+              (!_cups_strcasecmp(option, "PageSize") &&
+               !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) ||
+              (!_cups_strcasecmp(option, "PageRegion") &&
+               !_cups_strcasecmp(constptr->option->keyword, "PageSize"))))
            continue;
-         }
+
+         /*
+         * Get the current option choice...
+         */
 
           if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
                                     newopts)) == NULL)
           {
-           marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
-           value  = marked ? marked->choice : "";
+           if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
+               !_cups_strcasecmp(constptr->option->keyword, "PageRegion"))
+           {
+             if ((value = cupsGetOption("PageSize", num_newopts,
+                                        newopts)) == NULL)
+                value = cupsGetOption("PageRegion", num_newopts, newopts);
+
+              if (!value)
+             {
+               if ((size = ppdPageSize(ppd, NULL)) != NULL)
+                 value = size->name;
+               else
+                 value = "";
+             }
+           }
+           else
+           {
+             marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
+             value  = marked ? marked->choice : "";
+           }
          }
 
-          if (strcasecmp(value, constptr->option->defchoice))
-         {
-           num_newopts = cupsAddOption(constptr->option->keyword,
-                                       constptr->option->defchoice,
-                                       num_newopts, &newopts);
-            changed     = 1;
-         }
-        }
+         if (!_cups_strncasecmp(value, "Custom.", 7))
+           value = "Custom";
 
-        if (ignored && !changed)
-       {
-        /*
-         * No choice, have to back out this selection...
+         /*
+         * Try the default choice...
          */
 
-          if ((value = cupsGetOption(ignored->keyword, num_newopts,
-                                    newopts)) == NULL)
-          {
-           marked = ppdFindMarkedChoice(ppd, ignored->keyword);
-           value  = marked ? marked->choice : "";
-         }
+          test = NULL;
 
-          if (strcasecmp(value, ignored->defchoice))
+          if (_cups_strcasecmp(value, constptr->option->defchoice) &&
+             (test = ppd_test_constraints(ppd, constptr->option->keyword,
+                                          constptr->option->defchoice,
+                                          num_newopts, newopts,
+                                          _PPD_OPTION_CONSTRAINTS)) == NULL)
          {
-           num_newopts = cupsAddOption(ignored->keyword, ignored->defchoice,
+          /*
+           * That worked...
+           */
+
+           num_newopts = cupsAddOption(constptr->option->keyword,
+                                       constptr->option->defchoice,
                                        num_newopts, &newopts);
             changed     = 1;
          }
-       }
-      }
+         else
+         {
+          /*
+           * Try each choice instead...
+           */
+
+            for (j = constptr->option->num_choices,
+                    cptr = constptr->option->choices;
+                j > 0;
+                j --, cptr ++)
+            {
+             cupsArrayDelete(test);
+             test = NULL;
+
+             if (_cups_strcasecmp(value, cptr->choice) &&
+                 _cups_strcasecmp(constptr->option->defchoice, cptr->choice) &&
+                 _cups_strcasecmp("Custom", cptr->choice) &&
+                 (test = ppd_test_constraints(ppd, constptr->option->keyword,
+                                              cptr->choice, num_newopts,
+                                              newopts,
+                                              _PPD_OPTION_CONSTRAINTS)) == NULL)
+             {
+              /*
+               * This choice works...
+               */
+
+               num_newopts = cupsAddOption(constptr->option->keyword,
+                                           cptr->choice, num_newopts,
+                                           &newopts);
+               changed     = 1;
+               break;
+             }
+           }
 
-      if (!changed)
-      {
-       DEBUG_puts("ppdResolveConflicts: Unable to automatically resolve "
-                  "constraint!");
-       goto error;
+           cupsArrayDelete(test);
+          }
+        }
       }
     }
 
+    if (!changed)
+    {
+      DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve "
+                "constraint!");
+      goto error;
+    }
+
     cupsArrayClear(pass);
     cupsArrayDelete(active);
+    active = NULL;
   }
 
+  if (tries >= 100)
+    goto error;
+
  /*
-  * Free either the old or the new options depending on whether we had to
-  * apply any resolvers...
+  * Free the caller's option array...
   */
 
-  if (resolvers)
-  {
-    cupsFreeOptions(*num_options, *options);
-    *num_options = num_newopts;
-    *options     = newopts;
-  }
+  cupsFreeOptions(*num_options, *options);
+
+ /*
+  * If Collate is the option we are testing, add it here.  Otherwise, remove
+  * any Collate option from the resolve list since the filters automatically
+  * handle manual collation...
+  */
+
+  if (option && !_cups_strcasecmp(option, "Collate"))
+    num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
   else
-    cupsFreeOptions(num_newopts, newopts);
+    num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
+
+ /*
+  * Return the new list of options to the caller...
+  */
+
+  *num_options = num_newopts;
+  *options     = newopts;
 
   cupsArrayDelete(pass);
   cupsArrayDelete(resolvers);
 
   cupsArrayRestore(ppd->sorted_attrs);
 
+  DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts));
+#ifdef DEBUG
+  for (i = 0; i < num_newopts; i ++)
+    DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i,
+                  newopts[i].name, newopts[i].value));
+#endif /* DEBUG */
+
   return (1);
 
  /*
@@ -403,15 +566,125 @@ cupsResolveConflicts(
 
   cupsFreeOptions(num_newopts, newopts);
 
+  cupsArrayDelete(active);
   cupsArrayDelete(pass);
   cupsArrayDelete(resolvers);
 
   cupsArrayRestore(ppd->sorted_attrs);
 
+  DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!");
+
   return (0);
 }
 
 
+/*
+ * 'ppdConflicts()' - Check to see if there are any conflicts among the
+ *                    marked option choices.
+ *
+ * The returned value is the same as returned by @link ppdMarkOption@.
+ */
+
+int                                    /* O - Number of conflicts found */
+ppdConflicts(ppd_file_t *ppd)          /* I - PPD to check */
+{
+  int                  i,              /* Looping variable */
+                       conflicts;      /* Number of conflicts */
+  cups_array_t         *active;        /* Active conflicts */
+  _ppd_cups_uiconsts_t *c;             /* Current constraints */
+  _ppd_cups_uiconst_t  *cptr;          /* Current constraint */
+  ppd_option_t *o;                     /* Current option */
+
+
+  if (!ppd)
+    return (0);
+
+ /*
+  * Clear all conflicts...
+  */
+
+  cupsArraySave(ppd->options);
+
+  for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
+    o->conflicted = 0;
+
+  cupsArrayRestore(ppd->options);
+
+ /*
+  * Test for conflicts...
+  */
+
+  active    = ppd_test_constraints(ppd, NULL, NULL, 0, NULL,
+                                   _PPD_ALL_CONSTRAINTS);
+  conflicts = cupsArrayCount(active);
+
+ /*
+  * Loop through all of the UI constraints and flag any options
+  * that conflict...
+  */
+
+  for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
+       c;
+       c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
+  {
+    for (i = c->num_constraints, cptr = c->constraints;
+         i > 0;
+        i --, cptr ++)
+      cptr->option->conflicted = 1;
+  }
+
+  cupsArrayDelete(active);
+
+ /*
+  * Return the number of conflicts found...
+  */
+
+  return (conflicts);
+}
+
+
+/*
+ * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
+ *                              an installable option.
+ *
+ * This function tests whether a particular option choice is available based
+ * on constraints against options in the "InstallableOptions" group.
+ *
+ * @since CUPS 1.4/OS X 10.6@
+ */
+
+int                                    /* O - 1 if conflicting, 0 if not conflicting */
+ppdInstallableConflict(
+    ppd_file_t *ppd,                   /* I - PPD file */
+    const char *option,                        /* I - Option */
+    const char *choice)                        /* I - Choice */
+{
+  cups_array_t *active;                /* Active conflicts */
+
+
+  DEBUG_printf(("2ppdInstallableConflict(ppd=%p, option=\"%s\", choice=\"%s\")",
+                ppd, option, choice));
+
+ /*
+  * Range check input...
+  */
+
+  if (!ppd || !option || !choice)
+    return (0);
+
+ /*
+  * Test constraints using the new option...
+  */
+
+  active = ppd_test_constraints(ppd, option, choice, 0, NULL,
+                               _PPD_INSTALLABLE_CONSTRAINTS);
+
+  cupsArrayDelete(active);
+
+  return (active != NULL);
+}
+
+
 /*
  * 'ppd_is_installable()' - Determine whether an option is in the
  *                          InstallableOptions group.
@@ -431,7 +704,7 @@ ppd_is_installable(
     for (i = installable->num_options, option = installable->options;
          i > 0;
         i --, option ++)
-      if (!strcasecmp(option->keyword, name))
+      if (!_cups_strcasecmp(option->keyword, name))
         return (1);
   }
 
@@ -458,6 +731,8 @@ ppd_load_constraints(ppd_file_t *ppd)       /* I - PPD file */
                *ptr;                   /* Pointer into option or choice */
 
 
+  DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd));
+
  /*
   * Create an array to hold the constraint data...
   */
@@ -471,228 +746,217 @@ ppd_load_constraints(ppd_file_t *ppd)   /* I - PPD file */
   for (i = ppd->num_groups, installable = ppd->groups;
        i > 0;
        i --, installable ++)
-    if (!strcasecmp(installable->name, "InstallableOptions"))
+    if (!_cups_strcasecmp(installable->name, "InstallableOptions"))
       break;
 
   if (i <= 0)
     installable = NULL;
 
  /*
-  * See what kind of constraint data we have in the PPD...
+  * Load old-style [Non]UIConstraints data...
   */
 
-  if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL)
+  for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
   {
    /*
-    * Load new-style cupsUIConstraints data...
+    * Weed out nearby duplicates, since the PPD spec requires that you
+    * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
     */
 
-    for (; constattr;
-         constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
-    {
-      if (!constattr->value)
-      {
-        DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
-        continue;
-      }
+    if (i > 1 &&
+       !_cups_strcasecmp(oldconst[0].option1, oldconst[1].option2) &&
+       !_cups_strcasecmp(oldconst[0].choice1, oldconst[1].choice2) &&
+       !_cups_strcasecmp(oldconst[0].option2, oldconst[1].option1) &&
+       !_cups_strcasecmp(oldconst[0].choice2, oldconst[1].choice1))
+      continue;
 
-      for (i = 0, vptr = strchr(constattr->value, '*');
-           vptr;
-          i ++, vptr = strchr(vptr + 1, '*'));
+   /*
+    * Allocate memory...
+    */
 
-      if (i == 0)
-      {
-        DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
-        continue;
-      }
+    if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
+    {
+      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+                "UIConstraints!");
+      return;
+    }
 
-      if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
-      {
-        DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
-                  "cupsUIConstraints!");
-        return;
-      }
+    if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
+    {
+      free(consts);
+      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+                "UIConstraints!");
+      return;
+    }
 
-      if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
-      {
-        free(consts);
-        DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
-                  "cupsUIConstraints!");
-        return;
-      }
+   /*
+    * Fill in the information...
+    */
 
-      consts->num_constraints = i;
-      consts->constraints     = constptr;
+    consts->num_constraints = 2;
+    consts->constraints     = constptr;
 
-      strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
+    if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) &&
+       !_cups_strcasecmp(oldconst->choice1, "True"))
+    {
+      constptr[0].option      = ppdFindOption(ppd, oldconst->option1 + 6);
+      constptr[0].choice      = ppdFindChoice(constptr[0].option, "Custom");
+      constptr[0].installable = 0;
+    }
+    else
+    {
+      constptr[0].option      = ppdFindOption(ppd, oldconst->option1);
+      constptr[0].choice      = ppdFindChoice(constptr[0].option,
+                                             oldconst->choice1);
+      constptr[0].installable = ppd_is_installable(installable,
+                                                  oldconst->option1);
+    }
 
-      for (i = 0, vptr = strchr(constattr->value, '*');
-           vptr;
-          i ++, vptr = strchr(vptr + 1, '*'), constptr ++)
-      {
-       /*
-        * Extract "*Option Choice" or just "*Option"...
-       */
+    if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
+    {
+      DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
+                   oldconst->option1, oldconst->choice1));
+      free(consts->constraints);
+      free(consts);
+      continue;
+    }
 
-        for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
-         if (ptr < (option + sizeof(option) - 1))
-           *ptr++ = *vptr;
+    if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) &&
+       !_cups_strcasecmp(oldconst->choice2, "True"))
+    {
+      constptr[1].option      = ppdFindOption(ppd, oldconst->option2 + 6);
+      constptr[1].choice      = ppdFindChoice(constptr[1].option, "Custom");
+      constptr[1].installable = 0;
+    }
+    else
+    {
+      constptr[1].option      = ppdFindOption(ppd, oldconst->option2);
+      constptr[1].choice      = ppdFindChoice(constptr[1].option,
+                                             oldconst->choice2);
+      constptr[1].installable = ppd_is_installable(installable,
+                                                  oldconst->option2);
+    }
 
-        *ptr = '\0';
+    if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
+    {
+      DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
+                   oldconst->option2, oldconst->choice2));
+      free(consts->constraints);
+      free(consts);
+      continue;
+    }
 
-        while (isspace(*vptr & 255))
-         vptr ++;
+    consts->installable = constptr[0].installable || constptr[1].installable;
 
-        if (*vptr == '*')
-       {
-         vptr --;
-         choice[0] = '\0';
-       }
-       else
-       {
-         for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
-           if (ptr < (choice + sizeof(choice) - 1))
-             *ptr++ = *vptr;
+   /*
+    * Add it to the constraints array...
+    */
 
-         *ptr = '\0';
-       }
+    cupsArrayAdd(ppd->cups_uiconstraints, consts);
+  }
 
-        if (!strncasecmp(option, "Custom", 6) && !strcasecmp(choice, "True"))
-       {
-         _cups_strcpy(option, option + 6);
-         strcpy(choice, "Custom");
-       }
+ /*
+  * Then load new-style constraints...
+  */
 
-        constptr->option      = ppdFindOption(ppd, option);
-        constptr->choice      = ppdFindChoice(constptr->option, choice);
-        constptr->installable = ppd_is_installable(installable, option);
-       consts->installable   |= constptr->installable;
+  for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL);
+       constattr;
+       constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
+  {
+    if (!constattr->value)
+    {
+      DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
+      continue;
+    }
 
-        if (!constptr->option)
-       {
-         DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n", option));
-         break;
-       }
-      }
+    for (i = 0, vptr = strchr(constattr->value, '*');
+        vptr;
+        i ++, vptr = strchr(vptr + 1, '*'));
 
-      if (!vptr)
-        cupsArrayAdd(ppd->cups_uiconstraints, consts);
-      else
-      {
-        free(consts->constraints);
-       free(consts);
-      }
+    if (i == 0)
+    {
+      DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
+      continue;
     }
-  }
-  else
-  {
-   /*
-    * Load old-style [Non]UIConstraints data...
-    */
 
-    for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
+    if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
     {
-     /*
-      * Weed out nearby duplicates, since the PPD spec requires that you
-      * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
-      */
-
-      if (i > 1 &&
-          !strcasecmp(oldconst[0].option1, oldconst[1].option2) &&
-         !strcasecmp(oldconst[0].choice1, oldconst[1].choice2) &&
-         !strcasecmp(oldconst[0].option2, oldconst[1].option1) &&
-         !strcasecmp(oldconst[0].choice2, oldconst[1].choice1))
-        continue;
+      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+                "cupsUIConstraints!");
+      return;
+    }
 
-     /*
-      * Allocate memory...
-      */
+    if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
+    {
+      free(consts);
+      DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
+                "cupsUIConstraints!");
+      return;
+    }
 
-      if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
-      {
-        DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
-                  "UIConstraints!");
-        return;
-      }
+    consts->num_constraints = i;
+    consts->constraints     = constptr;
 
-      if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
-      {
-        free(consts);
-        DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
-                  "UIConstraints!");
-        return;
-      }
+    strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
 
+    for (i = 0, vptr = strchr(constattr->value, '*');
+        vptr;
+        i ++, vptr = strchr(vptr, '*'), constptr ++)
+    {
      /*
-      * Fill in the information...
+      * Extract "*Option Choice" or just "*Option"...
       */
 
-      consts->num_constraints = 2;
-      consts->constraints     = constptr;
+      for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++)
+       if (ptr < (option + sizeof(option) - 1))
+         *ptr++ = *vptr;
 
-      if (!strncasecmp(oldconst->option1, "Custom", 6) &&
-          !strcasecmp(oldconst->choice1, "True"))
-      {
-       constptr[0].option      = ppdFindOption(ppd, oldconst->option1 + 6);
-       constptr[0].choice      = ppdFindChoice(constptr[0].option, "Custom");
-        constptr[0].installable = 0;
-      }
-      else
-      {
-       constptr[0].option      = ppdFindOption(ppd, oldconst->option1);
-       constptr[0].choice      = ppdFindChoice(constptr[0].option,
-                                               oldconst->choice1);
-       constptr[0].installable = ppd_is_installable(installable,
-                                                    oldconst->option1);
-      }
+      *ptr = '\0';
 
-      if (!constptr[0].option)
-      {
-        DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
-                     oldconst->option1));
-        free(consts->constraints);
-       free(consts);
-       continue;
-      }
+      while (_cups_isspace(*vptr))
+       vptr ++;
 
-      if (!strncasecmp(oldconst->option2, "Custom", 6) &&
-          !strcasecmp(oldconst->choice2, "True"))
-      {
-       constptr[1].option      = ppdFindOption(ppd, oldconst->option2 + 6);
-       constptr[1].choice      = ppdFindChoice(constptr[1].option, "Custom");
-        constptr[1].installable = 0;
-      }
+      if (*vptr == '*')
+       choice[0] = '\0';
       else
       {
-       constptr[1].option      = ppdFindOption(ppd, oldconst->option2);
-       constptr[1].choice      = ppdFindChoice(constptr[1].option,
-                                               oldconst->choice2);
-       constptr[1].installable = ppd_is_installable(installable,
-                                                    oldconst->option2);
+       for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++)
+         if (ptr < (choice + sizeof(choice) - 1))
+           *ptr++ = *vptr;
+
+       *ptr = '\0';
       }
 
-      if (!constptr->option)
+      if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True"))
       {
-        DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
-                     oldconst->option2));
-        free(consts->constraints);
-       free(consts);
-       continue;
+       _cups_strcpy(option, option + 6);
+       strlcpy(choice, "Custom", sizeof(choice));
       }
 
-      consts->installable = constptr[0].installable || constptr[1].installable;
+      constptr->option      = ppdFindOption(ppd, option);
+      constptr->choice      = ppdFindChoice(constptr->option, choice);
+      constptr->installable = ppd_is_installable(installable, option);
+      consts->installable   |= constptr->installable;
 
-     /*
-      * Add it to the constraints array...
-      */
+      if (!constptr->option || (!constptr->choice && choice[0]))
+      {
+       DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
+                     option, choice));
+       break;
+      }
+    }
 
+    if (!vptr)
       cupsArrayAdd(ppd->cups_uiconstraints, consts);
+    else
+    {
+      free(consts->constraints);
+      free(consts);
     }
   }
 }
 
 
-
 /*
  * 'ppd_test_constraints()' - See if any constraints are active.
  */
@@ -700,6 +964,8 @@ ppd_load_constraints(ppd_file_t *ppd)       /* I - PPD file */
 static cups_array_t *                  /* O - Array of active constraints */
 ppd_test_constraints(
     ppd_file_t    *ppd,                        /* I - PPD file */
+    const char    *option,             /* I - Current option */
+    const char    *choice,             /* I - Current choice */
     int           num_options,         /* I - Number of additional options */
     cups_option_t *options,            /* I - Additional options */
     int           which)               /* I - Which constraints to test */
@@ -710,28 +976,78 @@ ppd_test_constraints(
   ppd_choice_t         key,            /* Search key */
                        *marked;        /* Marked choice */
   cups_array_t         *active = NULL; /* Active constraints */
-  const char           *value;         /* Current value */
+  const char           *value,         /* Current value */
+                       *firstvalue;    /* AP_FIRSTPAGE_Keyword value */
+  char                 firstpage[255]; /* AP_FIRSTPAGE_Keyword string */
+
 
+  DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", "
+                "num_options=%d, options=%p, which=%d)", ppd, option, choice,
+               num_options, options, which));
 
   if (!ppd->cups_uiconstraints)
     ppd_load_constraints(ppd);
 
+  DEBUG_printf(("9ppd_test_constraints: %d constraints!",
+               cupsArrayCount(ppd->cups_uiconstraints)));
+
   cupsArraySave(ppd->marked);
 
   for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
        consts;
        consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
   {
-    if (which != _PPD_ALL_CONSTRAINTS && which != consts->installable)
-      continue;
+    DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", "
+                  "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
+                 "option2=\"%s\", choice2=\"%s\", ...",
+                 consts->installable, consts->resolver, consts->num_constraints,
+                 consts->constraints[0].option->keyword,
+                 consts->constraints[0].choice ?
+                     consts->constraints[0].choice->choice : "",
+                 consts->constraints[1].option->keyword,
+                 consts->constraints[1].choice ?
+                     consts->constraints[1].choice->choice : ""));
+
+    if (consts->installable && which < _PPD_INSTALLABLE_CONSTRAINTS)
+      continue;                                /* Skip installable option constraint */
+
+    if (!consts->installable && which == _PPD_INSTALLABLE_CONSTRAINTS)
+      continue;                                /* Skip non-installable option constraint */
+
+    if (which == _PPD_OPTION_CONSTRAINTS && option)
+    {
+     /*
+      * Skip constraints that do not involve the current option...
+      */
+
+      for (i = consts->num_constraints, constptr = consts->constraints;
+          i > 0;
+          i --, constptr ++)
+      {
+        if (!_cups_strcasecmp(constptr->option->keyword, option))
+         break;
+
+        if (!_cups_strncasecmp(option, "AP_FIRSTPAGE_", 13) &&
+           !_cups_strcasecmp(constptr->option->keyword, option + 13))
+         break;
+      }
+
+      if (!i)
+        continue;
+    }
+
+    DEBUG_puts("9ppd_test_constraints: Testing...");
 
     for (i = consts->num_constraints, constptr = consts->constraints;
          i > 0;
         i --, constptr ++)
     {
+      DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr->option->keyword,
+                   constptr->choice ? constptr->choice->choice : ""));
+
       if (constptr->choice &&
-          (!strcasecmp(constptr->option->keyword, "PageSize") ||
-           !strcasecmp(constptr->option->keyword, "PageRegion")))
+          (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
+           !_cups_strcasecmp(constptr->option->keyword, "PageRegion")))
       {
        /*
         * PageSize and PageRegion are used depending on the selected input slot
@@ -739,7 +1055,14 @@ ppd_test_constraints(
        * of an individual option...
        */
 
-        if ((value = cupsGetOption("PageSize", num_options, options)) == NULL)
+        if (option && choice &&
+           (!_cups_strcasecmp(option, "PageSize") ||
+            !_cups_strcasecmp(option, "PageRegion")))
+       {
+         value = choice;
+        }
+       else if ((value = cupsGetOption("PageSize", num_options,
+                                       options)) == NULL)
          if ((value = cupsGetOption("PageRegion", num_options,
                                     options)) == NULL)
            if ((value = cupsGetOption("media", num_options, options)) == NULL)
@@ -750,37 +1073,120 @@ ppd_test_constraints(
                value = size->name;
            }
 
-        if (!value || strcasecmp(value, constptr->choice->choice))
+        if (value && !_cups_strncasecmp(value, "Custom.", 7))
+         value = "Custom";
+
+        if (option && choice &&
+           (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") ||
+            !_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion")))
+       {
+         firstvalue = choice;
+        }
+       else if ((firstvalue = cupsGetOption("AP_FIRSTPAGE_PageSize",
+                                            num_options, options)) == NULL)
+         firstvalue = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options,
+                                    options);
+
+        if (firstvalue && !_cups_strncasecmp(firstvalue, "Custom.", 7))
+         firstvalue = "Custom";
+
+        if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
+           (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
+       {
+         DEBUG_puts("9ppd_test_constraints: NO");
          break;
+       }
       }
       else if (constptr->choice)
       {
-        if ((value = cupsGetOption(constptr->option->keyword, num_options,
-                                  options)) != NULL)
+       /*
+        * Compare against the constrained choice...
+       */
+
+        if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword))
+       {
+         if (!_cups_strncasecmp(choice, "Custom.", 7))
+           value = "Custom";
+         else
+           value = choice;
+       }
+        else if ((value = cupsGetOption(constptr->option->keyword, num_options,
+                                       options)) != NULL)
         {
-         if (strcasecmp(value, constptr->choice->choice))
-           break;
+         if (!_cups_strncasecmp(value, "Custom.", 7))
+           value = "Custom";
+       }
+        else if (constptr->choice->marked)
+         value = constptr->choice->choice;
+       else
+         value = NULL;
+
+       /*
+        * Now check AP_FIRSTPAGE_option...
+       */
+
+        snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s",
+                constptr->option->keyword);
+
+        if (option && choice && !_cups_strcasecmp(option, firstpage))
+       {
+         if (!_cups_strncasecmp(choice, "Custom.", 7))
+           firstvalue = "Custom";
+         else
+           firstvalue = choice;
+       }
+        else if ((firstvalue = cupsGetOption(firstpage, num_options,
+                                            options)) != NULL)
+        {
+         if (!_cups_strncasecmp(firstvalue, "Custom.", 7))
+           firstvalue = "Custom";
+       }
+       else
+         firstvalue = NULL;
+
+        DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value,
+                     firstvalue));
+
+        if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
+           (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
+       {
+         DEBUG_puts("9ppd_test_constraints: NO");
+         break;
+       }
+      }
+      else if (option && choice &&
+               !_cups_strcasecmp(option, constptr->option->keyword))
+      {
+       if (!_cups_strcasecmp(choice, "None") || !_cups_strcasecmp(choice, "Off") ||
+           !_cups_strcasecmp(choice, "False"))
+       {
+         DEBUG_puts("9ppd_test_constraints: NO");
+         break;
        }
-        else if (!constptr->choice->marked)
-          break;
       }
       else if ((value = cupsGetOption(constptr->option->keyword, num_options,
-                                     options)) != NULL)
+                                     options)) != NULL)
       {
-       if (!strcasecmp(value, "None") || !strcasecmp(value, "Off") ||
-           !strcasecmp(value, "False"))
-          break;
+       if (!_cups_strcasecmp(value, "None") || !_cups_strcasecmp(value, "Off") ||
+           !_cups_strcasecmp(value, "False"))
+       {
+         DEBUG_puts("9ppd_test_constraints: NO");
+         break;
+       }
       }
       else
       {
-        key.option = constptr->option;
+       key.option = constptr->option;
 
        if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key))
-               != NULL &&
-           (!strcasecmp(marked->choice, "None") ||
-            !strcasecmp(marked->choice, "Off") ||
-            !strcasecmp(marked->choice, "False")))
+               == NULL ||
+           (!_cups_strcasecmp(marked->choice, "None") ||
+            !_cups_strcasecmp(marked->choice, "Off") ||
+            !_cups_strcasecmp(marked->choice, "False")))
+       {
+         DEBUG_puts("9ppd_test_constraints: NO");
          break;
+       }
       }
     }
 
@@ -790,11 +1196,15 @@ ppd_test_constraints(
         active = cupsArrayNew(NULL, NULL);
 
       cupsArrayAdd(active, consts);
+      DEBUG_puts("9ppd_test_constraints: Added...");
     }
   }
 
   cupsArrayRestore(ppd->marked);
 
+  DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!",
+                cupsArrayCount(active)));
+
   return (active);
 }