4 * Option marking routines for CUPS.
6 * Copyright 2007-2012 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 "cups-private.h"
39 #include "ppd-private.h"
48 _PPD_NORMAL_CONSTRAINTS
,
49 _PPD_OPTION_CONSTRAINTS
,
50 _PPD_INSTALLABLE_CONSTRAINTS
,
59 static int ppd_is_installable(ppd_group_t
*installable
,
61 static void ppd_load_constraints(ppd_file_t
*ppd
);
62 static cups_array_t
*ppd_test_constraints(ppd_file_t
*ppd
,
66 cups_option_t
*options
,
71 * 'cupsGetConflicts()' - Get a list of conflicting options in a marked PPD.
73 * This function gets a list of options that would conflict if "option" and
74 * "choice" were marked in the PPD. You would typically call this function
75 * after marking the currently selected options in the PPD in order to
76 * determine whether a new option selection would cause a conflict.
78 * The number of conflicting options are returned with "options" pointing to
79 * the conflicting options. The returned option array must be freed using
80 * @link cupsFreeOptions@.
82 * @since CUPS 1.4/OS X 10.6@
85 int /* O - Number of conflicting options */
87 ppd_file_t
*ppd
, /* I - PPD file */
88 const char *option
, /* I - Option to test */
89 const char *choice
, /* I - Choice to test */
90 cups_option_t
**options
) /* O - Conflicting options */
92 int i
, /* Looping var */
93 num_options
; /* Number of conflicting options */
94 cups_array_t
*active
; /* Active conflicts */
95 _ppd_cups_uiconsts_t
*c
; /* Current constraints */
96 _ppd_cups_uiconst_t
*cptr
; /* Current constraint */
97 ppd_choice_t
*marked
; /* Marked choice */
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 (_cups_strcasecmp(cptr
->option
->keyword
, option
))
131 num_options
= cupsAddOption(cptr
->option
->keyword
,
132 cptr
->choice
->choice
, num_options
,
134 else if ((marked
= ppdFindMarkedChoice(ppd
,
135 cptr
->option
->keyword
)) != NULL
)
136 num_options
= cupsAddOption(cptr
->option
->keyword
, marked
->choice
,
137 num_options
, options
);
141 cupsArrayDelete(active
);
143 return (num_options
);
148 * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD.
150 * This function attempts to resolve any conflicts in a marked PPD, returning
151 * a list of option changes that are required to resolve them. On input,
152 * "num_options" and "options" contain any pending option changes that have
153 * not yet been marked, while "option" and "choice" contain the most recent
154 * selection which may or may not be in "num_options" or "options".
156 * On successful return, "num_options" and "options" are updated to contain
157 * "option" and "choice" along with any changes required to resolve conflicts
158 * specified in the PPD file and 1 is returned.
160 * If option conflicts cannot be resolved, "num_options" and "options" are not
161 * changed and 0 is returned.
163 * When resolving conflicts, @code cupsResolveConflicts@ does not consider
164 * changes to the current page size (@code media@, @code PageSize@, and
165 * @code PageRegion@) or to the most recent option specified in "option".
166 * Thus, if the only way to resolve a conflict is to change the page size
167 * or the option the user most recently changed, @code cupsResolveConflicts@
168 * will return 0 to indicate it was unable to resolve the conflicts.
170 * The @code cupsResolveConflicts@ function uses one of two sources of option
171 * constraint information. The preferred constraint information is defined by
172 * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this
173 * case, the PPD file provides constraint resolution actions.
175 * The backup constraint information is defined by the
176 * @code UIConstraints@ and @code NonUIConstraints@ attributes. These
177 * constraints are resolved algorithmically by first selecting the default
178 * choice for the conflicting option, then iterating over all possible choices
179 * until a non-conflicting option choice is found.
181 * @since CUPS 1.4/OS X 10.6@
184 int /* O - 1 on success, 0 on failure */
185 cupsResolveConflicts(
186 ppd_file_t
*ppd
, /* I - PPD file */
187 const char *option
, /* I - Newly selected option or @code NULL@ for none */
188 const char *choice
, /* I - Newly selected choice or @code NULL@ for none */
189 int *num_options
, /* IO - Number of additional selected options */
190 cups_option_t
**options
) /* IO - Additional selected options */
192 int i
, /* Looping var */
193 tries
, /* Number of tries */
194 num_newopts
; /* Number of new options */
195 cups_option_t
*newopts
; /* New options */
196 cups_array_t
*active
, /* Active constraints */
197 *pass
, /* Resolvers for this pass */
198 *resolvers
, /* Resolvers we have used */
199 *test
; /* Test array for conflicts */
200 _ppd_cups_uiconsts_t
*consts
; /* Current constraints */
201 _ppd_cups_uiconst_t
*constptr
; /* Current constraint */
202 ppd_attr_t
*resolver
; /* Current resolver */
203 const char *resval
; /* Pointer into resolver value */
204 char resoption
[PPD_MAX_NAME
],
205 /* Current resolver option */
206 reschoice
[PPD_MAX_NAME
],
207 /* Current resolver choice */
208 *resptr
, /* Pointer into option/choice */
209 firstpage
[255]; /* AP_FIRSTPAGE_Keyword string */
210 const char *value
; /* Selected option value */
211 int changed
; /* Did we change anything? */
212 ppd_choice_t
*marked
; /* Marked choice */
216 * Range check input...
219 if (!ppd
|| !num_options
|| !options
|| (option
== NULL
) != (choice
== NULL
))
223 * Build a shadow option array...
229 for (i
= 0; i
< *num_options
; i
++)
230 num_newopts
= cupsAddOption((*options
)[i
].name
, (*options
)[i
].value
,
231 num_newopts
, &newopts
);
232 if (option
&& _cups_strcasecmp(option
, "Collate"))
233 num_newopts
= cupsAddOption(option
, choice
, num_newopts
, &newopts
);
236 * Loop until we have no conflicts...
239 cupsArraySave(ppd
->sorted_attrs
);
242 pass
= cupsArrayNew((cups_array_func_t
)_cups_strcasecmp
, NULL
);
245 while (tries
< 100 &&
246 (active
= ppd_test_constraints(ppd
, NULL
, NULL
, num_newopts
, newopts
,
247 _PPD_ALL_CONSTRAINTS
)) != NULL
)
252 resolvers
= cupsArrayNew((cups_array_func_t
)_cups_strcasecmp
, NULL
);
254 for (consts
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(active
), changed
= 0;
256 consts
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(active
))
258 if (consts
->resolver
[0])
261 * Look up the resolver...
264 if (cupsArrayFind(pass
, consts
->resolver
))
265 continue; /* Already applied this resolver... */
267 if (cupsArrayFind(resolvers
, consts
->resolver
))
273 DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!",
278 if ((resolver
= ppdFindAttr(ppd
, "cupsUIResolver",
279 consts
->resolver
)) == NULL
)
281 DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!",
286 if (!resolver
->value
)
288 DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!",
294 * Add the options from the resolver...
297 cupsArrayAdd(pass
, consts
->resolver
);
298 cupsArrayAdd(resolvers
, consts
->resolver
);
300 for (resval
= resolver
->value
; *resval
&& !changed
;)
302 while (_cups_isspace(*resval
))
308 for (resval
++, resptr
= resoption
;
309 *resval
&& !_cups_isspace(*resval
);
311 if (resptr
< (resoption
+ sizeof(resoption
) - 1))
316 while (_cups_isspace(*resval
))
319 for (resptr
= reschoice
;
320 *resval
&& !_cups_isspace(*resval
);
322 if (resptr
< (reschoice
+ sizeof(reschoice
) - 1))
327 if (!resoption
[0] || !reschoice
[0])
331 * Is this the option we are changing?
334 snprintf(firstpage
, sizeof(firstpage
), "AP_FIRSTPAGE_%s", resoption
);
337 (!_cups_strcasecmp(resoption
, option
) ||
338 !_cups_strcasecmp(firstpage
, option
) ||
339 (!_cups_strcasecmp(option
, "PageSize") &&
340 !_cups_strcasecmp(resoption
, "PageRegion")) ||
341 (!_cups_strcasecmp(option
, "AP_FIRSTPAGE_PageSize") &&
342 !_cups_strcasecmp(resoption
, "PageSize")) ||
343 (!_cups_strcasecmp(option
, "AP_FIRSTPAGE_PageSize") &&
344 !_cups_strcasecmp(resoption
, "PageRegion")) ||
345 (!_cups_strcasecmp(option
, "PageRegion") &&
346 !_cups_strcasecmp(resoption
, "PageSize")) ||
347 (!_cups_strcasecmp(option
, "AP_FIRSTPAGE_PageRegion") &&
348 !_cups_strcasecmp(resoption
, "PageSize")) ||
349 (!_cups_strcasecmp(option
, "AP_FIRSTPAGE_PageRegion") &&
350 !_cups_strcasecmp(resoption
, "PageRegion"))))
357 if ((test
= ppd_test_constraints(ppd
, resoption
, reschoice
,
358 num_newopts
, newopts
,
359 _PPD_ALL_CONSTRAINTS
)) == NULL
)
368 cupsArrayDelete(test
);
371 * Add the option/choice from the resolver regardless of whether it
372 * worked; this makes sure that we can cascade several changes to
373 * make things resolve...
376 num_newopts
= cupsAddOption(resoption
, reschoice
, num_newopts
,
383 * Try resolving by choosing the default values for non-installable
384 * options, then by iterating through the possible choices...
387 int j
; /* Looping var */
388 ppd_choice_t
*cptr
; /* Current choice */
389 ppd_size_t
*size
; /* Current page size */
392 for (i
= consts
->num_constraints
, constptr
= consts
->constraints
;
397 * Can't resolve by changing an installable option...
400 if (constptr
->installable
)
404 * Is this the option we are changing?
408 (!_cups_strcasecmp(constptr
->option
->keyword
, option
) ||
409 (!_cups_strcasecmp(option
, "PageSize") &&
410 !_cups_strcasecmp(constptr
->option
->keyword
, "PageRegion")) ||
411 (!_cups_strcasecmp(option
, "PageRegion") &&
412 !_cups_strcasecmp(constptr
->option
->keyword
, "PageSize"))))
416 * Get the current option choice...
419 if ((value
= cupsGetOption(constptr
->option
->keyword
, num_newopts
,
422 if (!_cups_strcasecmp(constptr
->option
->keyword
, "PageSize") ||
423 !_cups_strcasecmp(constptr
->option
->keyword
, "PageRegion"))
425 if ((value
= cupsGetOption("PageSize", num_newopts
,
427 value
= cupsGetOption("PageRegion", num_newopts
, newopts
);
431 if ((size
= ppdPageSize(ppd
, NULL
)) != NULL
)
439 marked
= ppdFindMarkedChoice(ppd
, constptr
->option
->keyword
);
440 value
= marked
? marked
->choice
: "";
444 if (!_cups_strncasecmp(value
, "Custom.", 7))
448 * Try the default choice...
453 if (_cups_strcasecmp(value
, constptr
->option
->defchoice
) &&
454 (test
= ppd_test_constraints(ppd
, constptr
->option
->keyword
,
455 constptr
->option
->defchoice
,
456 num_newopts
, newopts
,
457 _PPD_OPTION_CONSTRAINTS
)) == NULL
)
463 num_newopts
= cupsAddOption(constptr
->option
->keyword
,
464 constptr
->option
->defchoice
,
465 num_newopts
, &newopts
);
471 * Try each choice instead...
474 for (j
= constptr
->option
->num_choices
,
475 cptr
= constptr
->option
->choices
;
479 cupsArrayDelete(test
);
482 if (_cups_strcasecmp(value
, cptr
->choice
) &&
483 _cups_strcasecmp(constptr
->option
->defchoice
, cptr
->choice
) &&
484 _cups_strcasecmp("Custom", cptr
->choice
) &&
485 (test
= ppd_test_constraints(ppd
, constptr
->option
->keyword
,
486 cptr
->choice
, num_newopts
,
488 _PPD_OPTION_CONSTRAINTS
)) == NULL
)
491 * This choice works...
494 num_newopts
= cupsAddOption(constptr
->option
->keyword
,
495 cptr
->choice
, num_newopts
,
502 cupsArrayDelete(test
);
510 DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve "
515 cupsArrayClear(pass
);
516 cupsArrayDelete(active
);
524 * Free the caller's option array...
527 cupsFreeOptions(*num_options
, *options
);
530 * If Collate is the option we are testing, add it here. Otherwise, remove
531 * any Collate option from the resolve list since the filters automatically
532 * handle manual collation...
535 if (option
&& !_cups_strcasecmp(option
, "Collate"))
536 num_newopts
= cupsAddOption(option
, choice
, num_newopts
, &newopts
);
538 num_newopts
= cupsRemoveOption("Collate", num_newopts
, &newopts
);
541 * Return the new list of options to the caller...
544 *num_options
= num_newopts
;
547 cupsArrayDelete(pass
);
548 cupsArrayDelete(resolvers
);
550 cupsArrayRestore(ppd
->sorted_attrs
);
552 DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts
));
554 for (i
= 0; i
< num_newopts
; i
++)
555 DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i
,
556 newopts
[i
].name
, newopts
[i
].value
));
562 * If we get here, we failed to resolve...
567 cupsFreeOptions(num_newopts
, newopts
);
569 cupsArrayDelete(active
);
570 cupsArrayDelete(pass
);
571 cupsArrayDelete(resolvers
);
573 cupsArrayRestore(ppd
->sorted_attrs
);
575 DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!");
582 * 'ppdConflicts()' - Check to see if there are any conflicts among the
583 * marked option choices.
585 * The returned value is the same as returned by @link ppdMarkOption@.
588 int /* O - Number of conflicts found */
589 ppdConflicts(ppd_file_t
*ppd
) /* I - PPD to check */
591 int i
, /* Looping variable */
592 conflicts
; /* Number of conflicts */
593 cups_array_t
*active
; /* Active conflicts */
594 _ppd_cups_uiconsts_t
*c
; /* Current constraints */
595 _ppd_cups_uiconst_t
*cptr
; /* Current constraint */
596 ppd_option_t
*o
; /* Current option */
603 * Clear all conflicts...
606 cupsArraySave(ppd
->options
);
608 for (o
= ppdFirstOption(ppd
); o
; o
= ppdNextOption(ppd
))
611 cupsArrayRestore(ppd
->options
);
614 * Test for conflicts...
617 active
= ppd_test_constraints(ppd
, NULL
, NULL
, 0, NULL
,
618 _PPD_ALL_CONSTRAINTS
);
619 conflicts
= cupsArrayCount(active
);
622 * Loop through all of the UI constraints and flag any options
626 for (c
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(active
);
628 c
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(active
))
630 for (i
= c
->num_constraints
, cptr
= c
->constraints
;
633 cptr
->option
->conflicted
= 1;
636 cupsArrayDelete(active
);
639 * Return the number of conflicts found...
647 * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
648 * an installable option.
650 * This function tests whether a particular option choice is available based
651 * on constraints against options in the "InstallableOptions" group.
653 * @since CUPS 1.4/OS X 10.6@
656 int /* O - 1 if conflicting, 0 if not conflicting */
657 ppdInstallableConflict(
658 ppd_file_t
*ppd
, /* I - PPD file */
659 const char *option
, /* I - Option */
660 const char *choice
) /* I - Choice */
662 cups_array_t
*active
; /* Active conflicts */
665 DEBUG_printf(("2ppdInstallableConflict(ppd=%p, option=\"%s\", choice=\"%s\")",
666 ppd
, option
, choice
));
669 * Range check input...
672 if (!ppd
|| !option
|| !choice
)
676 * Test constraints using the new option...
679 active
= ppd_test_constraints(ppd
, option
, choice
, 0, NULL
,
680 _PPD_INSTALLABLE_CONSTRAINTS
);
682 cupsArrayDelete(active
);
684 return (active
!= NULL
);
689 * 'ppd_is_installable()' - Determine whether an option is in the
690 * InstallableOptions group.
693 static int /* O - 1 if installable, 0 if normal */
695 ppd_group_t
*installable
, /* I - InstallableOptions group */
696 const char *name
) /* I - Option name */
700 int i
; /* Looping var */
701 ppd_option_t
*option
; /* Current option */
704 for (i
= installable
->num_options
, option
= installable
->options
;
707 if (!_cups_strcasecmp(option
->keyword
, name
))
716 * 'ppd_load_constraints()' - Load constraints from a PPD file.
720 ppd_load_constraints(ppd_file_t
*ppd
) /* I - PPD file */
722 int i
; /* Looping var */
723 ppd_const_t
*oldconst
; /* Current UIConstraints data */
724 ppd_attr_t
*constattr
; /* Current cupsUIConstraints attribute */
725 _ppd_cups_uiconsts_t
*consts
; /* Current cupsUIConstraints data */
726 _ppd_cups_uiconst_t
*constptr
; /* Current constraint */
727 ppd_group_t
*installable
; /* Installable options group */
728 const char *vptr
; /* Pointer into constraint value */
729 char option
[PPD_MAX_NAME
], /* Option name/MainKeyword */
730 choice
[PPD_MAX_NAME
], /* Choice/OptionKeyword */
731 *ptr
; /* Pointer into option or choice */
734 DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd
));
737 * Create an array to hold the constraint data...
740 ppd
->cups_uiconstraints
= cupsArrayNew(NULL
, NULL
);
743 * Find the installable options group if it exists...
746 for (i
= ppd
->num_groups
, installable
= ppd
->groups
;
748 i
--, installable
++)
749 if (!_cups_strcasecmp(installable
->name
, "InstallableOptions"))
756 * Load old-style [Non]UIConstraints data...
759 for (i
= ppd
->num_consts
, oldconst
= ppd
->consts
; i
> 0; i
--, oldconst
++)
762 * Weed out nearby duplicates, since the PPD spec requires that you
763 * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
767 !_cups_strcasecmp(oldconst
[0].option1
, oldconst
[1].option2
) &&
768 !_cups_strcasecmp(oldconst
[0].choice1
, oldconst
[1].choice2
) &&
769 !_cups_strcasecmp(oldconst
[0].option2
, oldconst
[1].option1
) &&
770 !_cups_strcasecmp(oldconst
[0].choice2
, oldconst
[1].choice1
))
777 if ((consts
= calloc(1, sizeof(_ppd_cups_uiconsts_t
))) == NULL
)
779 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
784 if ((constptr
= calloc(2, sizeof(_ppd_cups_uiconst_t
))) == NULL
)
787 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
793 * Fill in the information...
796 consts
->num_constraints
= 2;
797 consts
->constraints
= constptr
;
799 if (!_cups_strncasecmp(oldconst
->option1
, "Custom", 6) &&
800 !_cups_strcasecmp(oldconst
->choice1
, "True"))
802 constptr
[0].option
= ppdFindOption(ppd
, oldconst
->option1
+ 6);
803 constptr
[0].choice
= ppdFindChoice(constptr
[0].option
, "Custom");
804 constptr
[0].installable
= 0;
808 constptr
[0].option
= ppdFindOption(ppd
, oldconst
->option1
);
809 constptr
[0].choice
= ppdFindChoice(constptr
[0].option
,
811 constptr
[0].installable
= ppd_is_installable(installable
,
815 if (!constptr
[0].option
|| (!constptr
[0].choice
&& oldconst
->choice1
[0]))
817 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
818 oldconst
->option1
, oldconst
->choice1
));
819 free(consts
->constraints
);
824 if (!_cups_strncasecmp(oldconst
->option2
, "Custom", 6) &&
825 !_cups_strcasecmp(oldconst
->choice2
, "True"))
827 constptr
[1].option
= ppdFindOption(ppd
, oldconst
->option2
+ 6);
828 constptr
[1].choice
= ppdFindChoice(constptr
[1].option
, "Custom");
829 constptr
[1].installable
= 0;
833 constptr
[1].option
= ppdFindOption(ppd
, oldconst
->option2
);
834 constptr
[1].choice
= ppdFindChoice(constptr
[1].option
,
836 constptr
[1].installable
= ppd_is_installable(installable
,
840 if (!constptr
[1].option
|| (!constptr
[1].choice
&& oldconst
->choice2
[0]))
842 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
843 oldconst
->option2
, oldconst
->choice2
));
844 free(consts
->constraints
);
849 consts
->installable
= constptr
[0].installable
|| constptr
[1].installable
;
852 * Add it to the constraints array...
855 cupsArrayAdd(ppd
->cups_uiconstraints
, consts
);
859 * Then load new-style constraints...
862 for (constattr
= ppdFindAttr(ppd
, "cupsUIConstraints", NULL
);
864 constattr
= ppdFindNextAttr(ppd
, "cupsUIConstraints", NULL
))
866 if (!constattr
->value
)
868 DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
872 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
874 i
++, vptr
= strchr(vptr
+ 1, '*'));
878 DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
882 if ((consts
= calloc(1, sizeof(_ppd_cups_uiconsts_t
))) == NULL
)
884 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
885 "cupsUIConstraints!");
889 if ((constptr
= calloc(i
, sizeof(_ppd_cups_uiconst_t
))) == NULL
)
892 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
893 "cupsUIConstraints!");
897 consts
->num_constraints
= i
;
898 consts
->constraints
= constptr
;
900 strlcpy(consts
->resolver
, constattr
->spec
, sizeof(consts
->resolver
));
902 for (i
= 0, vptr
= strchr(constattr
->value
, '*');
904 i
++, vptr
= strchr(vptr
, '*'), constptr
++)
907 * Extract "*Option Choice" or just "*Option"...
910 for (vptr
++, ptr
= option
; *vptr
&& !_cups_isspace(*vptr
); vptr
++)
911 if (ptr
< (option
+ sizeof(option
) - 1))
916 while (_cups_isspace(*vptr
))
923 for (ptr
= choice
; *vptr
&& !_cups_isspace(*vptr
); vptr
++)
924 if (ptr
< (choice
+ sizeof(choice
) - 1))
930 if (!_cups_strncasecmp(option
, "Custom", 6) && !_cups_strcasecmp(choice
, "True"))
932 _cups_strcpy(option
, option
+ 6);
933 strlcpy(choice
, "Custom", sizeof(choice
));
936 constptr
->option
= ppdFindOption(ppd
, option
);
937 constptr
->choice
= ppdFindChoice(constptr
->option
, choice
);
938 constptr
->installable
= ppd_is_installable(installable
, option
);
939 consts
->installable
|= constptr
->installable
;
941 if (!constptr
->option
|| (!constptr
->choice
&& choice
[0]))
943 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
950 cupsArrayAdd(ppd
->cups_uiconstraints
, consts
);
953 free(consts
->constraints
);
961 * 'ppd_test_constraints()' - See if any constraints are active.
964 static cups_array_t
* /* O - Array of active constraints */
965 ppd_test_constraints(
966 ppd_file_t
*ppd
, /* I - PPD file */
967 const char *option
, /* I - Current option */
968 const char *choice
, /* I - Current choice */
969 int num_options
, /* I - Number of additional options */
970 cups_option_t
*options
, /* I - Additional options */
971 int which
) /* I - Which constraints to test */
973 int i
; /* Looping var */
974 _ppd_cups_uiconsts_t
*consts
; /* Current constraints */
975 _ppd_cups_uiconst_t
*constptr
; /* Current constraint */
976 ppd_choice_t key
, /* Search key */
977 *marked
; /* Marked choice */
978 cups_array_t
*active
= NULL
; /* Active constraints */
979 const char *value
, /* Current value */
980 *firstvalue
; /* AP_FIRSTPAGE_Keyword value */
981 char firstpage
[255]; /* AP_FIRSTPAGE_Keyword string */
984 DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", "
985 "num_options=%d, options=%p, which=%d)", ppd
, option
, choice
,
986 num_options
, options
, which
));
988 if (!ppd
->cups_uiconstraints
)
989 ppd_load_constraints(ppd
);
991 DEBUG_printf(("9ppd_test_constraints: %d constraints!",
992 cupsArrayCount(ppd
->cups_uiconstraints
)));
994 cupsArraySave(ppd
->marked
);
996 for (consts
= (_ppd_cups_uiconsts_t
*)cupsArrayFirst(ppd
->cups_uiconstraints
);
998 consts
= (_ppd_cups_uiconsts_t
*)cupsArrayNext(ppd
->cups_uiconstraints
))
1000 DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", "
1001 "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
1002 "option2=\"%s\", choice2=\"%s\", ...",
1003 consts
->installable
, consts
->resolver
, consts
->num_constraints
,
1004 consts
->constraints
[0].option
->keyword
,
1005 consts
->constraints
[0].choice
?
1006 consts
->constraints
[0].choice
->choice
: "",
1007 consts
->constraints
[1].option
->keyword
,
1008 consts
->constraints
[1].choice
?
1009 consts
->constraints
[1].choice
->choice
: ""));
1011 if (consts
->installable
&& which
< _PPD_INSTALLABLE_CONSTRAINTS
)
1012 continue; /* Skip installable option constraint */
1014 if (!consts
->installable
&& which
== _PPD_INSTALLABLE_CONSTRAINTS
)
1015 continue; /* Skip non-installable option constraint */
1017 if (which
== _PPD_OPTION_CONSTRAINTS
&& option
)
1020 * Skip constraints that do not involve the current option...
1023 for (i
= consts
->num_constraints
, constptr
= consts
->constraints
;
1027 if (!_cups_strcasecmp(constptr
->option
->keyword
, option
))
1030 if (!_cups_strncasecmp(option
, "AP_FIRSTPAGE_", 13) &&
1031 !_cups_strcasecmp(constptr
->option
->keyword
, option
+ 13))
1039 DEBUG_puts("9ppd_test_constraints: Testing...");
1041 for (i
= consts
->num_constraints
, constptr
= consts
->constraints
;
1045 DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr
->option
->keyword
,
1046 constptr
->choice
? constptr
->choice
->choice
: ""));
1048 if (constptr
->choice
&&
1049 (!_cups_strcasecmp(constptr
->option
->keyword
, "PageSize") ||
1050 !_cups_strcasecmp(constptr
->option
->keyword
, "PageRegion")))
1053 * PageSize and PageRegion are used depending on the selected input slot
1054 * and manual feed mode. Validate against the selected page size instead
1055 * of an individual option...
1058 if (option
&& choice
&&
1059 (!_cups_strcasecmp(option
, "PageSize") ||
1060 !_cups_strcasecmp(option
, "PageRegion")))
1064 else if ((value
= cupsGetOption("PageSize", num_options
,
1066 if ((value
= cupsGetOption("PageRegion", num_options
,
1068 if ((value
= cupsGetOption("media", num_options
, options
)) == NULL
)
1070 ppd_size_t
*size
= ppdPageSize(ppd
, NULL
);
1076 if (value
&& !_cups_strncasecmp(value
, "Custom.", 7))
1079 if (option
&& choice
&&
1080 (!_cups_strcasecmp(option
, "AP_FIRSTPAGE_PageSize") ||
1081 !_cups_strcasecmp(option
, "AP_FIRSTPAGE_PageRegion")))
1083 firstvalue
= choice
;
1085 else if ((firstvalue
= cupsGetOption("AP_FIRSTPAGE_PageSize",
1086 num_options
, options
)) == NULL
)
1087 firstvalue
= cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options
,
1090 if (firstvalue
&& !_cups_strncasecmp(firstvalue
, "Custom.", 7))
1091 firstvalue
= "Custom";
1093 if ((!value
|| _cups_strcasecmp(value
, constptr
->choice
->choice
)) &&
1094 (!firstvalue
|| _cups_strcasecmp(firstvalue
, constptr
->choice
->choice
)))
1096 DEBUG_puts("9ppd_test_constraints: NO");
1100 else if (constptr
->choice
)
1103 * Compare against the constrained choice...
1106 if (option
&& choice
&& !_cups_strcasecmp(option
, constptr
->option
->keyword
))
1108 if (!_cups_strncasecmp(choice
, "Custom.", 7))
1113 else if ((value
= cupsGetOption(constptr
->option
->keyword
, num_options
,
1116 if (!_cups_strncasecmp(value
, "Custom.", 7))
1119 else if (constptr
->choice
->marked
)
1120 value
= constptr
->choice
->choice
;
1125 * Now check AP_FIRSTPAGE_option...
1128 snprintf(firstpage
, sizeof(firstpage
), "AP_FIRSTPAGE_%s",
1129 constptr
->option
->keyword
);
1131 if (option
&& choice
&& !_cups_strcasecmp(option
, firstpage
))
1133 if (!_cups_strncasecmp(choice
, "Custom.", 7))
1134 firstvalue
= "Custom";
1136 firstvalue
= choice
;
1138 else if ((firstvalue
= cupsGetOption(firstpage
, num_options
,
1141 if (!_cups_strncasecmp(firstvalue
, "Custom.", 7))
1142 firstvalue
= "Custom";
1147 DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value
,
1150 if ((!value
|| _cups_strcasecmp(value
, constptr
->choice
->choice
)) &&
1151 (!firstvalue
|| _cups_strcasecmp(firstvalue
, constptr
->choice
->choice
)))
1153 DEBUG_puts("9ppd_test_constraints: NO");
1157 else if (option
&& choice
&&
1158 !_cups_strcasecmp(option
, constptr
->option
->keyword
))
1160 if (!_cups_strcasecmp(choice
, "None") || !_cups_strcasecmp(choice
, "Off") ||
1161 !_cups_strcasecmp(choice
, "False"))
1163 DEBUG_puts("9ppd_test_constraints: NO");
1167 else if ((value
= cupsGetOption(constptr
->option
->keyword
, num_options
,
1170 if (!_cups_strcasecmp(value
, "None") || !_cups_strcasecmp(value
, "Off") ||
1171 !_cups_strcasecmp(value
, "False"))
1173 DEBUG_puts("9ppd_test_constraints: NO");
1179 key
.option
= constptr
->option
;
1181 if ((marked
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
))
1183 (!_cups_strcasecmp(marked
->choice
, "None") ||
1184 !_cups_strcasecmp(marked
->choice
, "Off") ||
1185 !_cups_strcasecmp(marked
->choice
, "False")))
1187 DEBUG_puts("9ppd_test_constraints: NO");
1196 active
= cupsArrayNew(NULL
, NULL
);
1198 cupsArrayAdd(active
, consts
);
1199 DEBUG_puts("9ppd_test_constraints: Added...");
1203 cupsArrayRestore(ppd
->marked
);
1205 DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!",
1206 cupsArrayCount(active
)));