4 * Option marking routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * PostScript is a trademark of Adobe Systems, Inc.
17 * This file is subject to the Apple OS-Developed Software exception.
21 * cupsGetConflicts() - Get a list of conflicting options in a marked
23 * cupsResolveConflicts() - Resolve conflicts in a marked PPD.
24 * ppdConflicts() - Check to see if there are any conflicts among
25 * the marked option choices.
26 * ppdInstallableConflict() - Test whether an option choice conflicts with an
28 * ppd_is_installable() - Determine whether an option is in the
29 * InstallableOptions group.
30 * ppd_load_constraints() - Load constraints from a PPD file.
31 * ppd_test_constraints() - See if any constraints are active.
35 * Include necessary headers...
38 #include "ppd-private.h"
49 _PPD_NORMAL_CONSTRAINTS
,
50 _PPD_OPTION_CONSTRAINTS
,
51 _PPD_INSTALLABLE_CONSTRAINTS
,
60 static int ppd_is_installable(ppd_group_t
*installable
,
62 static void ppd_load_constraints(ppd_file_t
*ppd
);
63 static cups_array_t
*ppd_test_constraints(ppd_file_t
*ppd
,
67 cups_option_t
*options
,
72 * 'cupsGetConflicts()' - Get a list of conflicting options in a marked PPD.
74 * This function gets a list of options that would conflict if "option" and
75 * "choice" were marked in the PPD. You would typically call this function
76 * after marking the currently selected options in the PPD in order to
77 * determine whether a new option selection would cause a conflict.
79 * The number of conflicting options are returned with "options" pointing to
80 * the conflicting options. The returned option array must be freed using
81 * @link cupsFreeOptions@.
83 * @since CUPS 1.4/Mac OS X 10.6@
86 int /* O - Number of conflicting options */
88 ppd_file_t
*ppd
, /* I - PPD file */
89 const char *option
, /* I - Option to test */
90 const char *choice
, /* I - Choice to test */
91 cups_option_t
**options
) /* O - Conflicting options */
93 int i
, /* Looping var */
94 num_options
; /* Number of conflicting options */
95 cups_array_t
*active
; /* Active conflicts */
96 _ppd_cups_uiconsts_t
*c
; /* Current constraints */
97 _ppd_cups_uiconst_t
*cptr
; /* Current constraint */
101 * Range check input...
107 if (!ppd
|| !option
|| !choice
|| !options
)
111 * Test for conflicts...
114 active
= ppd_test_constraints(ppd
, option
, choice
, 0, NULL
,
115 _PPD_ALL_CONSTRAINTS
);
118 * Loop through all of the UI constraints and add any options that conflict...
121 for (num_options
= 0, c
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(active
);
123 c
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(active
))
125 for (i
= c
->num_constraints
, cptr
= c
->constraints
;
128 if (strcasecmp(cptr
->option
->keyword
, option
))
129 num_options
= cupsAddOption(cptr
->option
->keyword
, cptr
->choice
->choice
,
130 num_options
, options
);
133 cupsArrayDelete(active
);
135 return (num_options
);
140 * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD.
142 * This function attempts to resolve any conflicts in a marked PPD, returning
143 * a list of option changes that are required to resolve them. On input,
144 * "num_options" and "options" contain any pending option changes that have
145 * not yet been marked, while "option" and "choice" contain the most recent
146 * selection which may or may not be in "num_options" or "options".
148 * On successful return, "num_options" and "options" are updated to contain
149 * "option" and "choice" along with any changes required to resolve conflicts
150 * specified in the PPD file and 1 is returned.
152 * If option conflicts cannot be resolved, "num_options" and "options" are not
153 * changed and 0 is returned.
155 * When resolving conflicts, @code cupsResolveConflicts@ does not consider
156 * changes to the current page size (@code media@, @code PageSize@, and
157 * @code PageRegion@) or to the most recent option specified in "option".
158 * Thus, if the only way to resolve a conflict is to change the page size
159 * or the option the user most recently changed, @code cupsResolveConflicts@
160 * will return 0 to indicate it was unable to resolve the conflicts.
162 * The @code cupsResolveConflicts@ function uses one of two sources of option
163 * constraint information. The preferred constraint information is defined by
164 * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this
165 * case, the PPD file provides constraint resolution actions.
167 * The backup constraint information is defined by the
168 * @code UIConstraints@ and @code NonUIConstraints@ attributes. These
169 * constraints are resolved algorithmically by first selecting the default
170 * choice for the conflicting option, then iterating over all possible choices
171 * until a non-conflicting option choice is found.
173 * @since CUPS 1.4/Mac OS X 10.6@
176 int /* O - 1 on success, 0 on failure */
177 cupsResolveConflicts(
178 ppd_file_t
*ppd
, /* I - PPD file */
179 const char *option
, /* I - Newly selected option or @code NULL@ for none */
180 const char *choice
, /* I - Newly selected choice or @code NULL@ for none */
181 int *num_options
, /* IO - Number of additional selected options */
182 cups_option_t
**options
) /* IO - Additional selected options */
184 int i
, /* Looping var */
185 tries
, /* Number of tries */
186 num_newopts
; /* Number of new options */
187 cups_option_t
*newopts
; /* New options */
188 cups_array_t
*active
, /* Active constraints */
189 *pass
, /* Resolvers for this pass */
190 *resolvers
, /* Resolvers we have used */
191 *test
; /* Test array for conflicts */
192 _ppd_cups_uiconsts_t
*consts
; /* Current constraints */
193 _ppd_cups_uiconst_t
*constptr
; /* Current constraint */
194 ppd_attr_t
*resolver
; /* Current resolver */
195 const char *resval
; /* Pointer into resolver value */
196 char resoption
[PPD_MAX_NAME
],
197 /* Current resolver option */
198 reschoice
[PPD_MAX_NAME
],
199 /* Current resolver choice */
200 *resptr
; /* Pointer into option/choice */
201 const char *value
; /* Selected option value */
202 int changed
; /* Did we change anything? */
203 ppd_choice_t
*marked
; /* Marked choice */
207 * Range check input...
210 if (!ppd
|| !num_options
|| !options
|| (option
== NULL
) != (choice
== NULL
))
214 * Build a shadow option array...
220 for (i
= 0; i
< *num_options
; i
++)
221 num_newopts
= cupsAddOption((*options
)[i
].name
, (*options
)[i
].value
,
222 num_newopts
, &newopts
);
223 if (option
&& strcasecmp(option
, "Collate"))
224 num_newopts
= cupsAddOption(option
, choice
, num_newopts
, &newopts
);
227 * Loop until we have no conflicts...
230 cupsArraySave(ppd
->sorted_attrs
);
233 pass
= cupsArrayNew((cups_array_func_t
)strcasecmp
, NULL
);
236 while (tries
< 100 &&
237 (active
= ppd_test_constraints(ppd
, NULL
, NULL
, num_newopts
, newopts
,
238 _PPD_ALL_CONSTRAINTS
)) != NULL
)
243 resolvers
= cupsArrayNew((cups_array_func_t
)strcasecmp
, NULL
);
245 for (consts
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(active
), changed
= 0;
247 consts
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(active
))
249 if (consts
->resolver
[0])
252 * Look up the resolver...
255 if (cupsArrayFind(pass
, consts
->resolver
))
256 continue; /* Already applied this resolver... */
258 if (cupsArrayFind(resolvers
, consts
->resolver
))
264 DEBUG_printf(("1ppdResolveConflicts: Resolver loop with %s!",
269 if ((resolver
= ppdFindAttr(ppd
, "cupsUIResolver",
270 consts
->resolver
)) == NULL
)
272 DEBUG_printf(("1ppdResolveConflicts: Resolver %s not found!",
277 if (!resolver
->value
)
279 DEBUG_printf(("1ppdResolveConflicts: Resolver %s has no value!",
285 * Add the options from the resolver...
288 cupsArrayAdd(pass
, consts
->resolver
);
289 cupsArrayAdd(resolvers
, consts
->resolver
);
291 for (resval
= resolver
->value
; *resval
&& !changed
;)
293 while (isspace(*resval
& 255))
299 for (resval
++, resptr
= resoption
;
300 *resval
&& !isspace(*resval
& 255);
302 if (resptr
< (resoption
+ sizeof(resoption
) - 1))
307 while (isspace(*resval
& 255))
310 for (resptr
= reschoice
;
311 *resval
&& !isspace(*resval
& 255);
313 if (resptr
< (reschoice
+ sizeof(reschoice
) - 1))
318 if (!resoption
[0] || !reschoice
[0])
322 * Is this the option we are changing?
326 (!strcasecmp(resoption
, option
) ||
327 (!strcasecmp(option
, "PageSize") &&
328 !strcasecmp(resoption
, "PageRegion")) ||
329 (!strcasecmp(option
, "PageRegion") &&
330 !strcasecmp(resoption
, "PageSize"))))
337 if ((test
= ppd_test_constraints(ppd
, resoption
, reschoice
,
338 num_newopts
, newopts
,
339 _PPD_ALL_CONSTRAINTS
)) == NULL
)
348 cupsArrayDelete(test
);
351 * Add the option/choice from the resolver regardless of whether it
352 * worked; this makes sure that we can cascade several changes to
353 * make things resolve...
356 num_newopts
= cupsAddOption(resoption
, reschoice
, num_newopts
,
363 * Try resolving by choosing the default values for non-installable
364 * options, then by iterating through the possible choices...
367 int j
; /* Looping var */
368 ppd_choice_t
*cptr
; /* Current choice */
369 ppd_size_t
*size
; /* Current page size */
372 for (i
= consts
->num_constraints
, constptr
= consts
->constraints
;
377 * Can't resolve by changing an installable option...
380 if (constptr
->installable
)
384 * Is this the option we are changing?
388 (!strcasecmp(constptr
->option
->keyword
, option
) ||
389 (!strcasecmp(option
, "PageSize") &&
390 !strcasecmp(constptr
->option
->keyword
, "PageRegion")) ||
391 (!strcasecmp(option
, "PageRegion") &&
392 !strcasecmp(constptr
->option
->keyword
, "PageSize"))))
396 * Get the current option choice...
399 if ((value
= cupsGetOption(constptr
->option
->keyword
, num_newopts
,
402 if (!strcasecmp(constptr
->option
->keyword
, "PageSize") ||
403 !strcasecmp(constptr
->option
->keyword
, "PageRegion"))
405 if ((value
= cupsGetOption("PageSize", num_newopts
,
407 value
= cupsGetOption("PageRegion", num_newopts
, newopts
);
411 if ((size
= ppdPageSize(ppd
, NULL
)) != NULL
)
419 marked
= ppdFindMarkedChoice(ppd
, constptr
->option
->keyword
);
420 value
= marked
? marked
->choice
: "";
424 if (!strncasecmp(value
, "Custom.", 7))
428 * Try the default choice...
433 if (strcasecmp(value
, constptr
->option
->defchoice
) &&
434 (test
= ppd_test_constraints(ppd
, constptr
->option
->keyword
,
435 constptr
->option
->defchoice
,
436 num_newopts
, newopts
,
437 _PPD_OPTION_CONSTRAINTS
)) == NULL
)
443 num_newopts
= cupsAddOption(constptr
->option
->keyword
,
444 constptr
->option
->defchoice
,
445 num_newopts
, &newopts
);
451 * Try each choice instead...
454 for (j
= constptr
->option
->num_choices
,
455 cptr
= constptr
->option
->choices
;
459 cupsArrayDelete(test
);
462 if (strcasecmp(value
, cptr
->choice
) &&
463 strcasecmp(constptr
->option
->defchoice
, cptr
->choice
) &&
464 strcasecmp("Custom", cptr
->choice
) &&
465 (test
= ppd_test_constraints(ppd
, constptr
->option
->keyword
,
466 cptr
->choice
, num_newopts
,
468 _PPD_OPTION_CONSTRAINTS
)) == NULL
)
471 * This choice works...
474 num_newopts
= cupsAddOption(constptr
->option
->keyword
,
475 cptr
->choice
, num_newopts
,
482 cupsArrayDelete(test
);
489 DEBUG_puts("1ppdResolveConflicts: Unable to automatically resolve "
495 cupsArrayClear(pass
);
496 cupsArrayDelete(active
);
504 * Free the caller's option array...
507 cupsFreeOptions(*num_options
, *options
);
510 * If Collate is the option we are testing, add it here. Otherwise, remove
511 * any Collate option from the resolve list since the filters automatically
512 * handle manual collation...
515 if (option
&& !strcasecmp(option
, "Collate"))
516 num_newopts
= cupsAddOption(option
, choice
, num_newopts
, &newopts
);
518 num_newopts
= cupsRemoveOption("Collate", num_newopts
, &newopts
);
521 * Return the new list of options to the caller...
524 *num_options
= num_newopts
;
527 cupsArrayDelete(pass
);
528 cupsArrayDelete(resolvers
);
530 cupsArrayRestore(ppd
->sorted_attrs
);
532 DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts
));
534 for (i
= 0; i
< num_newopts
; i
++)
535 DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i
,
536 newopts
[i
].name
, newopts
[i
].value
));
542 * If we get here, we failed to resolve...
547 cupsFreeOptions(num_newopts
, newopts
);
549 cupsArrayDelete(active
);
550 cupsArrayDelete(pass
);
551 cupsArrayDelete(resolvers
);
553 cupsArrayRestore(ppd
->sorted_attrs
);
555 DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!");
562 * 'ppdConflicts()' - Check to see if there are any conflicts among the
563 * marked option choices.
565 * The returned value is the same as returned by @link ppdMarkOption@.
568 int /* O - Number of conflicts found */
569 ppdConflicts(ppd_file_t
*ppd
) /* I - PPD to check */
571 int i
, /* Looping variable */
572 conflicts
; /* Number of conflicts */
573 cups_array_t
*active
; /* Active conflicts */
574 _ppd_cups_uiconsts_t
*c
; /* Current constraints */
575 _ppd_cups_uiconst_t
*cptr
; /* Current constraint */
576 ppd_option_t
*o
; /* Current option */
583 * Clear all conflicts...
586 cupsArraySave(ppd
->options
);
588 for (o
= ppdFirstOption(ppd
); o
; o
= ppdNextOption(ppd
))
591 cupsArrayRestore(ppd
->options
);
594 * Test for conflicts...
597 active
= ppd_test_constraints(ppd
, NULL
, NULL
, 0, NULL
,
598 _PPD_ALL_CONSTRAINTS
);
599 conflicts
= cupsArrayCount(active
);
602 * Loop through all of the UI constraints and flag any options
606 for (c
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(active
);
608 c
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(active
))
610 for (i
= c
->num_constraints
, cptr
= c
->constraints
;
613 cptr
->option
->conflicted
= 1;
616 cupsArrayDelete(active
);
619 * Return the number of conflicts found...
627 * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
628 * an installable option.
630 * This function tests whether a particular option choice is available based
631 * on constraints against options in the "InstallableOptions" group.
633 * @since CUPS 1.4/Mac OS X 10.6@
636 int /* O - 1 if conflicting, 0 if not conflicting */
637 ppdInstallableConflict(
638 ppd_file_t
*ppd
, /* I - PPD file */
639 const char *option
, /* I - Option */
640 const char *choice
) /* I - Choice */
642 cups_array_t
*active
; /* Active conflicts */
645 DEBUG_printf(("2ppdInstallableConflict(ppd=%p, option=\"%s\", choice=\"%s\")",
646 ppd
, option
, choice
));
649 * Range check input...
652 if (!ppd
|| !option
|| !choice
)
656 * Test constraints using the new option...
659 active
= ppd_test_constraints(ppd
, option
, choice
, 0, NULL
,
660 _PPD_INSTALLABLE_CONSTRAINTS
);
662 cupsArrayDelete(active
);
664 return (active
!= NULL
);
669 * 'ppd_is_installable()' - Determine whether an option is in the
670 * InstallableOptions group.
673 static int /* O - 1 if installable, 0 if normal */
675 ppd_group_t
*installable
, /* I - InstallableOptions group */
676 const char *name
) /* I - Option name */
680 int i
; /* Looping var */
681 ppd_option_t
*option
; /* Current option */
684 for (i
= installable
->num_options
, option
= installable
->options
;
687 if (!strcasecmp(option
->keyword
, name
))
696 * 'ppd_load_constraints()' - Load constraints from a PPD file.
700 ppd_load_constraints(ppd_file_t
*ppd
) /* I - PPD file */
702 int i
; /* Looping var */
703 ppd_const_t
*oldconst
; /* Current UIConstraints data */
704 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
705 _ppd_cups_uiconsts_t
*consts
; /* Current cupsUIConstraints data */
706 _ppd_cups_uiconst_t
*constptr
; /* Current constraint */
707 ppd_group_t
*installable
; /* Installable options group */
708 const char *vptr
; /* Pointer into constraint value */
709 char option
[PPD_MAX_NAME
], /* Option name/MainKeyword */
710 choice
[PPD_MAX_NAME
], /* Choice/OptionKeyword */
711 *ptr
; /* Pointer into option or choice */
714 DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd
));
717 * Create an array to hold the constraint data...
720 ppd
->cups_uiconstraints
= cupsArrayNew(NULL
, NULL
);
723 * Find the installable options group if it exists...
726 for (i
= ppd
->num_groups
, installable
= ppd
->groups
;
728 i
--, installable
++)
729 if (!strcasecmp(installable
->name
, "InstallableOptions"))
736 * Load old-style [Non]UIConstraints data...
739 for (i
= ppd
->num_consts
, oldconst
= ppd
->consts
; i
> 0; i
--, oldconst
++)
742 * Weed out nearby duplicates, since the PPD spec requires that you
743 * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
747 !strcasecmp(oldconst
[0].option1
, oldconst
[1].option2
) &&
748 !strcasecmp(oldconst
[0].choice1
, oldconst
[1].choice2
) &&
749 !strcasecmp(oldconst
[0].option2
, oldconst
[1].option1
) &&
750 !strcasecmp(oldconst
[0].choice2
, oldconst
[1].choice1
))
757 if ((consts
= calloc(1, sizeof(_ppd_cups_uiconsts_t
))) == NULL
)
759 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
764 if ((constptr
= calloc(2, sizeof(_ppd_cups_uiconst_t
))) == NULL
)
767 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
773 * Fill in the information...
776 consts
->num_constraints
= 2;
777 consts
->constraints
= constptr
;
779 if (!strncasecmp(oldconst
->option1
, "Custom", 6) &&
780 !strcasecmp(oldconst
->choice1
, "True"))
782 constptr
[0].option
= ppdFindOption(ppd
, oldconst
->option1
+ 6);
783 constptr
[0].choice
= ppdFindChoice(constptr
[0].option
, "Custom");
784 constptr
[0].installable
= 0;
788 constptr
[0].option
= ppdFindOption(ppd
, oldconst
->option1
);
789 constptr
[0].choice
= ppdFindChoice(constptr
[0].option
,
791 constptr
[0].installable
= ppd_is_installable(installable
,
795 if (!constptr
[0].option
|| (!constptr
[0].choice
&& oldconst
->choice1
[0]))
797 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
798 oldconst
->option1
, oldconst
->choice1
));
799 free(consts
->constraints
);
804 if (!strncasecmp(oldconst
->option2
, "Custom", 6) &&
805 !strcasecmp(oldconst
->choice2
, "True"))
807 constptr
[1].option
= ppdFindOption(ppd
, oldconst
->option2
+ 6);
808 constptr
[1].choice
= ppdFindChoice(constptr
[1].option
, "Custom");
809 constptr
[1].installable
= 0;
813 constptr
[1].option
= ppdFindOption(ppd
, oldconst
->option2
);
814 constptr
[1].choice
= ppdFindChoice(constptr
[1].option
,
816 constptr
[1].installable
= ppd_is_installable(installable
,
820 if (!constptr
[1].option
|| (!constptr
[1].choice
&& oldconst
->choice2
[0]))
822 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
823 oldconst
->option2
, oldconst
->choice2
));
824 free(consts
->constraints
);
829 consts
->installable
= constptr
[0].installable
|| constptr
[1].installable
;
832 * Add it to the constraints array...
835 cupsArrayAdd(ppd
->cups_uiconstraints
, consts
);
839 * Then load new-style constraints...
842 for (constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
);
844 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
846 if (!constattr
->value
)
848 DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
852 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
854 i
++, vptr
= strchr(vptr
+ 1, '*'));
858 DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
862 if ((consts
= calloc(1, sizeof(_ppd_cups_uiconsts_t
))) == NULL
)
864 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
865 "cupsUIConstraints!");
869 if ((constptr
= calloc(i
, sizeof(_ppd_cups_uiconst_t
))) == NULL
)
872 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
873 "cupsUIConstraints!");
877 consts
->num_constraints
= i
;
878 consts
->constraints
= constptr
;
880 strlcpy(consts
->resolver
, constattr
->spec
, sizeof(consts
->resolver
));
882 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
884 i
++, vptr
= strchr(vptr
, '*'), constptr
++)
887 * Extract "*Option Choice" or just "*Option"...
890 for (vptr
++, ptr
= option
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
891 if (ptr
< (option
+ sizeof(option
) - 1))
896 while (isspace(*vptr
& 255))
903 for (ptr
= choice
; *vptr
&& !isspace(*vptr
& 255); vptr
++)
904 if (ptr
< (choice
+ sizeof(choice
) - 1))
910 if (!strncasecmp(option
, "Custom", 6) && !strcasecmp(choice
, "True"))
912 _cups_strcpy(option
, option
+ 6);
913 strcpy(choice
, "Custom");
916 constptr
->option
= ppdFindOption(ppd
, option
);
917 constptr
->choice
= ppdFindChoice(constptr
->option
, choice
);
918 constptr
->installable
= ppd_is_installable(installable
, option
);
919 consts
->installable
|= constptr
->installable
;
921 if (!constptr
->option
|| (!constptr
->choice
&& choice
[0]))
923 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
930 cupsArrayAdd(ppd
->cups_uiconstraints
, consts
);
933 free(consts
->constraints
);
941 * 'ppd_test_constraints()' - See if any constraints are active.
944 static cups_array_t
* /* O - Array of active constraints */
945 ppd_test_constraints(
946 ppd_file_t
*ppd
, /* I - PPD file */
947 const char *option
, /* I - Current option */
948 const char *choice
, /* I - Current choice */
949 int num_options
, /* I - Number of additional options */
950 cups_option_t
*options
, /* I - Additional options */
951 int which
) /* I - Which constraints to test */
953 int i
; /* Looping var */
954 _ppd_cups_uiconsts_t
*consts
; /* Current constraints */
955 _ppd_cups_uiconst_t
*constptr
; /* Current constraint */
956 ppd_choice_t key
, /* Search key */
957 *marked
; /* Marked choice */
958 cups_array_t
*active
= NULL
; /* Active constraints */
959 const char *value
; /* Current value */
962 DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", "
963 "num_options=%d, options=%p, which=%d)", ppd
, option
, choice
,
964 num_options
, options
, which
));
966 if (!ppd
->cups_uiconstraints
)
967 ppd_load_constraints(ppd
);
969 DEBUG_printf(("9ppd_test_constraints: %d constraints!",
970 cupsArrayCount(ppd
->cups_uiconstraints
)));
972 cupsArraySave(ppd
->marked
);
974 for (consts
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(ppd
->cups_uiconstraints
);
976 consts
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(ppd
->cups_uiconstraints
))
978 DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", "
979 "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
980 "option2=\"%s\", choice2=\"%s\", ...",
981 consts
->installable
, consts
->resolver
, consts
->num_constraints
,
982 consts
->constraints
[0].option
->keyword
,
983 consts
->constraints
[0].choice
?
984 consts
->constraints
[0].choice
->choice
: "",
985 consts
->constraints
[1].option
->keyword
,
986 consts
->constraints
[1].choice
?
987 consts
->constraints
[1].choice
->choice
: ""));
989 if (consts
->installable
&& which
< _PPD_INSTALLABLE_CONSTRAINTS
)
990 continue; /* Skip installable option constraint */
992 if (!consts
->installable
&& which
== _PPD_INSTALLABLE_CONSTRAINTS
)
993 continue; /* Skip non-installable option constraint */
995 if (which
== _PPD_OPTION_CONSTRAINTS
&& option
)
998 * Skip constraints that do not involve the current option...
1001 for (i
= consts
->num_constraints
, constptr
= consts
->constraints
;
1004 if (!strcasecmp(constptr
->option
->keyword
, option
))
1011 DEBUG_puts("9ppd_test_constraints: Testing...");
1013 for (i
= consts
->num_constraints
, constptr
= consts
->constraints
;
1017 DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr
->option
->keyword
,
1018 constptr
->choice
? constptr
->choice
->choice
: ""));
1020 if (constptr
->choice
&&
1021 (!strcasecmp(constptr
->option
->keyword
, "PageSize") ||
1022 !strcasecmp(constptr
->option
->keyword
, "PageRegion")))
1025 * PageSize and PageRegion are used depending on the selected input slot
1026 * and manual feed mode. Validate against the selected page size instead
1027 * of an individual option...
1030 if (option
&& choice
&&
1031 (!strcasecmp(option
, "PageSize") ||
1032 !strcasecmp(option
, "PageRegion")))
1036 else if ((value
= cupsGetOption("PageSize", num_options
,
1038 if ((value
= cupsGetOption("PageRegion", num_options
,
1040 if ((value
= cupsGetOption("media", num_options
, options
)) == NULL
)
1042 ppd_size_t
*size
= ppdPageSize(ppd
, NULL
);
1048 if (value
&& !strncasecmp(value
, "Custom.", 7))
1051 if (!value
|| strcasecmp(value
, constptr
->choice
->choice
))
1053 DEBUG_puts("9ppd_test_constraints: NO");
1057 else if (constptr
->choice
)
1059 if (option
&& choice
&& !strcasecmp(option
, constptr
->option
->keyword
))
1061 if (!strncasecmp(choice
, "Custom.", 7))
1066 if (strcasecmp(value
, constptr
->choice
->choice
))
1068 DEBUG_puts("9ppd_test_constraints: NO");
1072 else if ((value
= cupsGetOption(constptr
->option
->keyword
, num_options
,
1075 if (!strncasecmp(value
, "Custom.", 7))
1078 if (strcasecmp(value
, constptr
->choice
->choice
))
1080 DEBUG_puts("9ppd_test_constraints: NO");
1084 else if (!constptr
->choice
->marked
)
1086 DEBUG_puts("9ppd_test_constraints: NO");
1090 else if (option
&& choice
&&
1091 !strcasecmp(option
, constptr
->option
->keyword
))
1093 if (!strcasecmp(choice
, "None") || !strcasecmp(choice
, "Off") ||
1094 !strcasecmp(choice
, "False"))
1096 DEBUG_puts("9ppd_test_constraints: NO");
1100 else if ((value
= cupsGetOption(constptr
->option
->keyword
, num_options
,
1103 if (!strcasecmp(value
, "None") || !strcasecmp(value
, "Off") ||
1104 !strcasecmp(value
, "False"))
1106 DEBUG_puts("9ppd_test_constraints: NO");
1112 key
.option
= constptr
->option
;
1114 if ((marked
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
))
1116 (!strcasecmp(marked
->choice
, "None") ||
1117 !strcasecmp(marked
->choice
, "Off") ||
1118 !strcasecmp(marked
->choice
, "False")))
1120 DEBUG_puts("9ppd_test_constraints: NO");
1129 active
= cupsArrayNew(NULL
, NULL
);
1131 cupsArrayAdd(active
, consts
);
1132 DEBUG_puts("9ppd_test_constraints: Added...");
1136 cupsArrayRestore(ppd
->marked
);
1138 DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!",
1139 cupsArrayCount(active
)));