]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Add missing files.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 18 Jul 2008 18:56:19 +0000 (18:56 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 18 Jul 2008 18:56:19 +0000 (18:56 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@870 a1ca3aef-8c08-0410-bb20-df032aa958be

cups/conflicts.c [new file with mode: 0644]
cups/test2.ppd [new file with mode: 0644]

diff --git a/cups/conflicts.c b/cups/conflicts.c
new file mode 100644 (file)
index 0000000..79dbb41
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * "$Id$"
+ *
+ *   Option marking routines for the Common UNIX Printing System (CUPS).
+ *
+ *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *   PostScript is a trademark of Adobe Systems, Inc.
+ *
+ *   This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ *   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.
+ *   ppd_test_constraints()   - See if any constraints are active.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ppd-private.h"
+#include "string.h"
+#include "debug.h"
+
+
+/*
+ * Local constants...
+ */
+
+enum
+{
+  _PPD_NORMAL_CONSTRAINTS,
+  _PPD_INSTALLABLE_CONSTRAINTS,
+  _PPD_ALL_CONSTRAINTS
+};
+
+
+/*
+ * Local functions...
+ */
+
+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,
+                                             cups_option_t *options,
+                                             int which);
+
+
+/*
+ * '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...
+  */
+
+  conflicts = 0;
+
+  for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
+    o->conflicted = 0;
+
+ /*
+  * Test for conflicts...
+  */
+
+  active    = ppd_test_constraints(ppd, 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@
+ */
+
+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);
+}
+
+
+/*
+ * '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
+ * 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.
+ *
+ * @code ppdResolveConflicts@ 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.
+ *
+ * The backup constraint infomration 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.
+ *
+ * @since CUPS 1.4@
+ */
+
+int                                    /* O  - 1 on success, 0 on failure */
+cupsResolveConflicts(
+    ppd_file_t    *ppd,                        /* I  - PPD file */
+    const char    *option,             /* I  - Newly selected option or @code NULL@ for none */
+    const char    *choice,             /* I  - Newly selected choice or @code NULL@ for none */
+    int           *num_options,                /* IO - Number of additional selected options */
+    cups_option_t **options)           /* IO - Additional selected options */
+{
+  int                  i,              /* Looping var */
+                       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 */
+  _ppd_cups_uiconsts_t *consts;        /* Current constraints */
+  _ppd_cups_uiconst_t  *constptr;      /* Current constraint */
+  ppd_attr_t           *resolver;      /* Current resolver */
+  const char           *value;         /* Selected option value */
+  int                  changed;        /* Did we change anything? */
+  ppd_choice_t         *marked;        /* Marked choice */
+  ppd_option_t         *ignored;       /* Ignored option */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL))
+    return (0);
+
+ /*
+  * Build a shadow option array...
+  */
+
+  num_newopts = 0;
+  newopts     = NULL;
+
+  for (i = 0; i < *num_options; i ++)
+    num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value,
+                                num_newopts, &newopts);
+  if (option)
+    num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
+
+ /*
+  * Loop until we have no conflicts...
+  */
+
+  cupsArraySave(ppd->sorted_attrs);
+
+  resolvers = NULL;
+  pass      = cupsArrayNew((cups_array_func_t)strcasecmp, NULL);
+
+  while ((active = ppd_test_constraints(ppd, num_newopts, newopts,
+                                        _PPD_ALL_CONSTRAINTS)) != NULL)
+  {
+    if (!resolvers)
+      resolvers = cupsArrayNew((cups_array_func_t)strcasecmp, NULL);
+
+    for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0;
+         consts;
+        consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
+    {
+      if (consts->resolver[0])
+      {
+       /*
+        * Look up the resolver...
+       */
+
+        if (cupsArrayFind(pass, consts->resolver))
+         continue;                     /* Already applied this resolver... */
+
+        if (cupsArrayFind(resolvers, consts->resolver))
+       {
+        /*
+         * Resolver loop!
+         */
+
+         DEBUG_printf(("ppdResolveConflicts: Resolver loop with %s!\n",
+                       consts->resolver));
+          goto error;
+       }
+
+        if ((resolver = ppdFindAttr(ppd, "cupsUIResolver",
+                                   consts->resolver)) == NULL)
+        {
+         DEBUG_printf(("ppdResolveConflicts: Resolver %s not found!\n",
+                       consts->resolver));
+         goto error;
+       }
+
+        if (!resolver->value)
+       {
+         DEBUG_printf(("ppdResolveConflicts: Resolver %s has no value!\n",
+                       consts->resolver));
+         goto error;
+       }
+
+       /*
+        * Add the options from the resolver...
+       */
+
+        cupsArrayAdd(pass, consts->resolver);
+       cupsArrayAdd(resolvers, consts->resolver);
+
+        num_newopts = _ppdParseOptions(resolver->value, num_newopts, &newopts);
+       changed     = 1;
+      }
+      else
+      {
+       /*
+        * Try resolving by choosing the default values for non-installable
+       * options...
+       */
+
+        for (i = consts->num_constraints, constptr = consts->constraints,
+                ignored = NULL;
+            i > 0;
+            i --, constptr ++)
+       {
+         if (constptr->installable ||
+             !strcasecmp(constptr->option->keyword, "PageSize") ||
+             !strcasecmp(constptr->option->keyword, "PageRegion"))
+           continue;
+
+         if (option && !strcasecmp(constptr->option->keyword, option))
+         {
+           ignored = constptr->option;
+           continue;
+         }
+
+          if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
+                                    newopts)) == NULL)
+          {
+           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 (ignored && !changed)
+       {
+        /*
+         * No choice, have to back out this selection...
+         */
+
+          if ((value = cupsGetOption(ignored->keyword, num_newopts,
+                                    newopts)) == NULL)
+          {
+           marked = ppdFindMarkedChoice(ppd, ignored->keyword);
+           value  = marked ? marked->choice : "";
+         }
+
+          if (strcasecmp(value, ignored->defchoice))
+         {
+           num_newopts = cupsAddOption(ignored->keyword, ignored->defchoice,
+                                       num_newopts, &newopts);
+            changed     = 1;
+         }
+       }
+      }
+
+      if (!changed)
+      {
+       DEBUG_puts("ppdResolveConflicts: Unable to automatically resolve "
+                  "constraint!");
+       goto error;
+      }
+    }
+
+    cupsArrayClear(pass);
+    cupsArrayDelete(active);
+  }
+
+ /*
+  * Free either the old or the new options depending on whether we had to
+  * apply any resolvers...
+  */
+
+  if (resolvers)
+  {
+    cupsFreeOptions(*num_options, *options);
+    *num_options = num_newopts;
+    *options     = newopts;
+  }
+  else
+    cupsFreeOptions(num_newopts, newopts);
+
+  cupsArrayDelete(pass);
+  cupsArrayDelete(resolvers);
+
+  cupsArrayRestore(ppd->sorted_attrs);
+
+  return (1);
+
+ /*
+  * If we get here, we failed to resolve...
+  */
+
+  error:
+
+  cupsFreeOptions(num_newopts, newopts);
+
+  cupsArrayDelete(pass);
+  cupsArrayDelete(resolvers);
+
+  cupsArrayRestore(ppd->sorted_attrs);
+
+  return (0);
+}
+
+
+/*
+ * 'ppd_is_installable()' - Determine whether an option is in the
+ *                          InstallableOptions group.
+ */
+
+static int                             /* O - 1 if installable, 0 if normal */
+ppd_is_installable(
+    ppd_group_t *installable,          /* I - InstallableOptions group */
+    const char  *name)                 /* I - Option name */
+{
+  if (installable)
+  {
+    int                        i;              /* Looping var */
+    ppd_option_t       *option;        /* Current option */
+
+
+    for (i = installable->num_options, option = installable->options;
+         i > 0;
+        i --, option ++)
+      if (!strcasecmp(option->keyword, name))
+        return (1);
+  }
+
+  return (0);
+}
+
+
+/*
+ * 'ppd_load_constraints()' - Load constraints from a PPD file.
+ */
+
+static void
+ppd_load_constraints(ppd_file_t *ppd)  /* I - PPD file */
+{
+  int          i;                      /* Looping var */
+  ppd_const_t  *oldconst;              /* Current UIConstraints data */
+  ppd_attr_t   *constattr;             /* Current cupsUIConstraints attribute */
+  _ppd_cups_uiconsts_t *consts;        /* Current cupsUIConstraints data */
+  _ppd_cups_uiconst_t  *constptr;      /* Current constraint */
+  ppd_group_t  *installable;           /* Installable options group */
+  const char   *vptr;                  /* Pointer into constraint value */
+  char         option[PPD_MAX_NAME],   /* Option name/MainKeyword */
+               choice[PPD_MAX_NAME],   /* Choice/OptionKeyword */
+               *ptr;                   /* Pointer into option or choice */
+
+
+ /*
+  * Create an array to hold the constraint data...
+  */
+
+  ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL);
+
+ /*
+  * Find the installable options group if it exists...
+  */
+
+  for (i = ppd->num_groups, installable = ppd->groups;
+       i > 0;
+       i --, installable ++)
+    if (!strcasecmp(installable->name, "InstallableOptions"))
+      break;
+
+  if (i <= 0)
+    installable = NULL;
+
+ /*
+  * See what kind of constraint data we have in the PPD...
+  */
+
+  if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL)
+  {
+   /*
+    * Load new-style cupsUIConstraints data...
+    */
+
+    for (; constattr;
+         constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
+    {
+      if (!constattr->value)
+      {
+        DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
+        continue;
+      }
+
+      for (i = 0, vptr = strchr(constattr->value, '*');
+           vptr;
+          i ++, vptr = strchr(vptr + 1, '*'));
+
+      if (i == 0)
+      {
+        DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
+        continue;
+      }
+
+      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(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
+      {
+        free(consts);
+        DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
+                  "cupsUIConstraints!");
+        return;
+      }
+
+      consts->num_constraints = i;
+      consts->constraints     = constptr;
+
+      strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
+
+      for (i = 0, vptr = strchr(constattr->value, '*');
+           vptr;
+          i ++, vptr = strchr(vptr + 1, '*'), constptr ++)
+      {
+       /*
+        * Extract "*Option Choice" or just "*Option"...
+       */
+
+        for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
+         if (ptr < (option + sizeof(option) - 1))
+           *ptr++ = *vptr;
+
+        *ptr = '\0';
+
+        while (isspace(*vptr & 255))
+         vptr ++;
+
+        if (*vptr == '*')
+       {
+         vptr --;
+         choice[0] = '\0';
+       }
+       else
+       {
+         for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
+           if (ptr < (choice + sizeof(choice) - 1))
+             *ptr++ = *vptr;
+
+         *ptr = '\0';
+       }
+
+        if (!strncasecmp(option, "Custom", 6) && !strcasecmp(choice, "True"))
+       {
+         _cups_strcpy(option, option + 6);
+         strcpy(choice, "Custom");
+       }
+
+        constptr->option      = ppdFindOption(ppd, option);
+        constptr->choice      = ppdFindChoice(constptr->option, choice);
+        constptr->installable = ppd_is_installable(installable, option);
+       consts->installable   |= constptr->installable;
+
+        if (!constptr->option)
+       {
+         DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n", option));
+         break;
+       }
+      }
+
+      if (!vptr)
+        cupsArrayAdd(ppd->cups_uiconstraints, consts);
+      else
+      {
+        free(consts->constraints);
+       free(consts);
+      }
+    }
+  }
+  else
+  {
+   /*
+    * Load old-style [Non]UIConstraints data...
+    */
+
+    for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
+    {
+     /*
+      * 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;
+
+     /*
+      * Allocate memory...
+      */
+
+      if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
+      {
+        DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
+                  "UIConstraints!");
+        return;
+      }
+
+      if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
+      {
+        free(consts);
+        DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
+                  "UIConstraints!");
+        return;
+      }
+
+     /*
+      * Fill in the information...
+      */
+
+      consts->num_constraints = 2;
+      consts->constraints     = constptr;
+
+      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);
+      }
+
+      if (!constptr[0].option)
+      {
+        DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
+                     oldconst->option1));
+        free(consts->constraints);
+       free(consts);
+       continue;
+      }
+
+      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;
+      }
+      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);
+      }
+
+      if (!constptr->option)
+      {
+        DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
+                     oldconst->option2));
+        free(consts->constraints);
+       free(consts);
+       continue;
+      }
+
+      consts->installable = constptr[0].installable || constptr[1].installable;
+
+     /*
+      * Add it to the constraints array...
+      */
+
+      cupsArrayAdd(ppd->cups_uiconstraints, consts);
+    }
+  }
+}
+
+
+
+/*
+ * 'ppd_test_constraints()' - See if any constraints are active.
+ */
+
+static cups_array_t *                  /* O - Array of active constraints */
+ppd_test_constraints(
+    ppd_file_t    *ppd,                        /* I - PPD file */
+    int           num_options,         /* I - Number of additional options */
+    cups_option_t *options,            /* I - Additional options */
+    int           which)               /* I - Which constraints to test */
+{
+  int                  i;              /* Looping var */
+  _ppd_cups_uiconsts_t *consts;        /* Current constraints */
+  _ppd_cups_uiconst_t  *constptr;      /* Current constraint */
+  ppd_choice_t         key,            /* Search key */
+                       *marked;        /* Marked choice */
+  cups_array_t         *active = NULL; /* Active constraints */
+  const char           *value;         /* Current value */
+
+
+  if (!ppd->cups_uiconstraints)
+    ppd_load_constraints(ppd);
+
+  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;
+
+    for (i = consts->num_constraints, constptr = consts->constraints;
+         i > 0;
+        i --, constptr ++)
+    {
+      if (constptr->choice &&
+          (!strcasecmp(constptr->option->keyword, "PageSize") ||
+           !strcasecmp(constptr->option->keyword, "PageRegion")))
+      {
+       /*
+        * PageSize and PageRegion are used depending on the selected input slot
+       * and manual feed mode.  Validate against the selected page size instead
+       * of an individual option...
+       */
+
+        if ((value = cupsGetOption("PageSize", num_options, options)) == NULL)
+         if ((value = cupsGetOption("PageRegion", num_options,
+                                    options)) == NULL)
+           if ((value = cupsGetOption("media", num_options, options)) == NULL)
+           {
+             ppd_size_t *size = ppdPageSize(ppd, NULL);
+
+              if (size)
+               value = size->name;
+           }
+
+        if (!value || strcasecmp(value, constptr->choice->choice))
+         break;
+      }
+      else if (constptr->choice)
+      {
+        if ((value = cupsGetOption(constptr->option->keyword, num_options,
+                                  options)) != NULL)
+        {
+         if (strcasecmp(value, constptr->choice->choice))
+           break;
+       }
+        else if (!constptr->choice->marked)
+          break;
+      }
+      else if ((value = cupsGetOption(constptr->option->keyword, num_options,
+                                     options)) != NULL)
+      {
+       if (!strcasecmp(value, "None") || !strcasecmp(value, "Off") ||
+           !strcasecmp(value, "False"))
+          break;
+      }
+      else
+      {
+        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")))
+         break;
+      }
+    }
+
+    if (i <= 0)
+    {
+      if (!active)
+        active = cupsArrayNew(NULL, NULL);
+
+      cupsArrayAdd(active, consts);
+    }
+  }
+
+  cupsArrayRestore(ppd->marked);
+
+  return (active);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/cups/test2.ppd b/cups/test2.ppd
new file mode 100644 (file)
index 0000000..9cd9d22
--- /dev/null
@@ -0,0 +1,248 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test PPD file #2 for the Common UNIX Printing System (CUPS).
+*%
+*% This file is used to test the CUPS PPD API functions and cannot be
+*% used with any known printers.  Look at the PPD files in the "ppd"
+*% subdirectory as well as the CUPS web site for working PPD files.
+*%
+*% If you are a PPD file developer, consider using the PPD compiler (ppdc)
+*% to create your PPD files - not only will it save you time, it produces
+*% consistently high-quality files.
+*%
+*% Copyright 2007-2008 by Apple Inc.
+*% Copyright 2002-2006 by Easy Software Products.
+*% 
+*% These coded instructions, statements, and computer programs are the
+*% property of Apple Inc. and are protected by Federal copyright
+*% law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+*% which should have been included with this file.  If this file is
+*% file is missing or damaged, see the license at "http://www.cups.org/".
+*FormatVersion:        "4.3"
+*FileVersion:  "1.3"
+*LanguageVersion: English 
+*LanguageEncoding: ISOLatin1
+*PCFileName:   "TEST.PPD"
+*Manufacturer: "ESP"
+*Product:      "(Test2)"
+*cupsVersion:  1.4
+*ModelName:     "Test2"
+*ShortNickName: "Test2"
+*NickName:      "Test2 for CUPS"
+*PSVersion:    "(3010.000) 0"
+*LanguageLevel:        "3"
+*ColorDevice:  True
+*DefaultColorSpace: RGB
+*FileSystem:   False
+*Throughput:   "1"
+*LandscapeOrientation: Plus90
+*TTRasterizer: Type42
+
+*% These constraints are used to test ppdConflicts() and ppdResolveConflicts()
+*cupsUIConstraints envelope: "*PageSize Letter *InputSlot Envelope"
+*cupsUIConstraints envelope: "*PageRegion Letter *InputSlot Envelope"
+*cupsUIResolver envelope: "*InputSlot Manual"
+
+*cupsUIConstraints envphoto: "*PageSize Env10 *InputSlot Envelope *Quality Photo"
+*cupsUIConstraints envphoto: "*PageRegion Env10 *InputSlot Envelope *Quality Photo"
+*cupsUIResolver envphoto: "*Quality Normal"
+
+*% This constraint is used to test ppdInstallableConflict()
+*cupsUIConstraints: "*Duplex *InstalledDuplexer False"
+
+*% These constraints are used to test the loop detection code in ppdResolveConflicts()
+*cupsUIConstraints loop1: "*PageSize A4 *Quality Photo"
+*cupsUIResolver loop1: "*Quality Normal"
+*cupsUIConstraints loop2: "*PageSize A4 *Quality Normal"
+*cupsUIResolver loop2: "*PageSize Letter *Quality Draft"
+*cupsUIConstraints loop3: "*PageSize Letter *Quality Draft"
+*cupsUIResolver loop3: "*PageSize A4 *Quality Photo"
+
+*% For PageSize, we have put all of the translations in-line...
+*OpenUI *PageSize/Page Size: PickOne
+*fr.Translation PageSize/French Page Size: ""
+*fr_CA.Translation PageSize/French Canadian Page Size: ""
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter:    "PageSize=Letter"
+*fr.PageSize Letter/French US Letter: ""
+*fr_CA.PageSize Letter/French Canadian US Letter: ""
+*PageSize A4/A4:               "PageSize=A4"
+*fr.PageSize A4/French A4: ""
+*fr_CA.PageSize A4/French Canadian A4: ""
+*PageSize Env10/#10 Envelope:  "PageSize=Env10"
+*fr.PageSize Env10/French #10 Envelope: ""
+*fr_CA.PageSize Env10/French Canadian #10 Envelope: ""
+*CloseUI: *PageSize
+
+*% For PageRegion, we have separated the translations...
+*OpenUI *PageRegion/Page Region: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter:  "PageRegion=Letter"
+*PageRegion A4/A4:             "PageRegion=A4"
+*PageRegion Env10/#10 Envelope:        "PageRegion=Env10"
+*CloseUI: *PageRegion
+
+*fr.Translation PageRegion/French Page Region: ""
+*fr.PageRegion Letter/French US Letter: ""
+*fr.PageRegion A4/French A4: ""
+*fr.PageRegion Env10/French #10 Envelope: ""
+
+*fr_CA.Translation PageRegion/French Canadian Page Region: ""
+*fr_CA.PageRegion Letter/French Canadian US Letter: ""
+*fr_CA.PageRegion A4/French Canadian A4: ""
+*fr_CA.PageRegion Env10/French Canadian #10 Envelope: ""
+
+*DefaultImageableArea: Letter 
+*ImageableArea Letter: "18 36 594 756"
+*ImageableArea A4:     "18 36 577 806"
+*ImageableArea Env10:  "18 36 279 648"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter:        "612 792"
+*PaperDimension A4:    "595 842"
+*PaperDimension Env10: "297 684"
+
+*% Custom page size support
+*HWMargins:      0 0 0 0
+*NonUIOrderDependency: 100 AnySetup *CustomPageSize True
+*CustomPageSize True/Custom Page Size: "PageSize=Custom"
+*ParamCustomPageSize Width:        1 points 36 1080
+*ParamCustomPageSize Height:       2 points 36 86400
+*ParamCustomPageSize WidthOffset/Width Offset:  3 points 0 0
+*ParamCustomPageSize HeightOffset/Height Offset: 4 points 0 0
+*ParamCustomPageSize Orientation:  5 int 0 0
+
+*OpenUI *InputSlot/Input Slot: PickOne
+*OrderDependency: 20 AnySetup *InputSlot
+*DefaultInputSlot: Tray
+*InputSlot Tray/Tray: "InputSlot=Tray"
+*InputSlot Manual/Manual Feed: "InputSlot=Manual"
+*InputSlot Envelope/Envelope Feed: "InputSlot=Envelope"
+*CloseUI: *InputSlot
+
+*OpenUI *Quality/Output Mode: PickOne
+*OrderDependency: 20 AnySetup *Quality
+*DefaultQuality: Normal
+*Quality Draft: "Quality=Draft"
+*Quality Normal: "Quality=Normal"
+*Quality Photo: "Quality=Photo"
+*CloseUI: *Quality
+
+*OpenUI *Duplex/2-Sided Printing: PickOne
+*OrderDependency: 10 DocumentSetup *Duplex
+*DefaultDuplex: None
+*Duplex None/Off: "Duplex=None"
+*Duplex DuplexNoTumble/Long Edge: "Duplex=DuplexNoTumble"
+*Duplex DuplexTumble/Short Edge: "Duplex=DuplexTumble"
+*CloseUI: *Duplex
+
+*% Installable option...
+*OpenGroup: InstallableOptions/Installable Options
+*OpenUI InstalledDuplexer/Duplexer Installed: Boolean
+*DefaultInstalledDuplexer: False
+*InstalledDuplexer False: ""
+*InstalledDuplexer True: ""
+*CloseUI: *InstalledDuplexer
+*CloseGroup: InstallableOptions
+
+*% Custom options...
+*OpenGroup: Extended/Extended Options
+
+*OpenUI IntOption/Integer: PickOne
+*OrderDependency: 30 AnySetup *IntOption
+*DefaultIntOption: None
+*IntOption None: ""
+*IntOption 1: "IntOption=1"
+*IntOption 2: "IntOption=2"
+*IntOption 3: "IntOption=3"
+*CloseUI: *IntOption
+
+*CustomIntOption True/Custom Integer: "IntOption=Custom"
+*ParamCustomIntOption Integer: 1 int -100 100
+
+*OpenUI StringOption/String: PickOne
+*OrderDependency: 40 AnySetup *StringOption
+*DefaultStringOption: None
+*StringOption None: ""
+*StringOption foo: "StringOption=foo"
+*StringOption bar: "StringOption=bar"
+*CloseUI: *StringOption
+
+*CustomStringOption True/Custom String: "StringOption=Custom"
+*ParamCustomStringOption String: 1 string 1 10
+
+*CloseGroup: Extended
+
+*% IPP reasons for ppdLocalizeIPPReason tests
+*cupsIPPReason foo/Foo Reason: "http://foo/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/foo/bar.html"
+*End
+*fr.cupsIPPReason foo/La Foo Reason: "text:La%20Long%20
+text:Foo%20Reason
+http://foo/fr/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/fr/foo/bar.html"
+*End
+*zh_TW.cupsIPPReason foo/Number 1 Foo Reason: "text:Number%201%20
+text:Foo%20Reason
+http://foo/zh_TW/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/zh_TW/foo/bar.html"
+*End
+*zh.cupsIPPReason foo/Number 2 Foo Reason: "text:Number%202%20
+text:Foo%20Reason
+http://foo/zh/bar.html
+help:anchor='foo'%20bookID=Vendor%20Help
+/help/zh/foo/bar.html"
+*End
+
+*% Marker names for ppdLocalizeMarkerName tests
+*cupsMarkerName cyan/Cyan Toner: ""
+*fr.cupsMarkerName cyan/La Toner Cyan: ""
+*zh_TW.cupsMarkerName cyan/Number 1 Cyan Toner: ""
+*zh.cupsMarkerName cyan/Number 2 Cyan Toner: ""
+
+*DefaultFont: Courier
+*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM
+*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM
+*Font Bookman-Demi: Standard "(001.004S)" Standard ROM
+*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM
+*Font Bookman-Light: Standard "(001.004S)" Standard ROM
+*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM
+*Font Courier: Standard "(002.004S)" Standard ROM
+*Font Courier-Bold: Standard "(002.004S)" Standard ROM
+*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM
+*Font Courier-Oblique: Standard "(002.004S)" Standard ROM
+*Font Helvetica: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM
+*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM
+*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM
+*Font Palatino-Bold: Standard "(001.005S)" Standard ROM
+*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Italic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Roman: Standard "(001.005S)" Standard ROM
+*Font Symbol: Special "(001.007S)" Special ROM
+*Font Times-Bold: Standard "(001.007S)" Standard ROM
+*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM
+*Font Times-Italic: Standard "(001.007S)" Standard ROM
+*Font Times-Roman: Standard "(001.007S)" Standard ROM
+*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
+*Font ZapfDingbats: Special "(001.004S)" Standard ROM
+*%
+*% End of "$Id$".
+*%