]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/conflicts.c
a99810cd90f1f38e855b68e422626585f926457f
[thirdparty/cups.git] / cups / conflicts.c
1 /*
2 * "$Id$"
3 *
4 * Option marking routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
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/".
14 *
15 * PostScript is a trademark of Adobe Systems, Inc.
16 *
17 * This file is subject to the Apple OS-Developed Software exception.
18 *
19 * Contents:
20 *
21 * cupsResolveConflicts() - Resolve conflicts in a marked PPD.
22 * ppdConflicts() - Check to see if there are any conflicts among
23 * the marked option choices.
24 * ppdInstallableConflict() - Test whether an option choice conflicts with an
25 * installable option.
26 * ppd_is_installable() - Determine whether an option is in the
27 * InstallableOptions group.
28 * ppd_load_constraints() - Load constraints from a PPD file.
29 * ppd_test_constraints() - See if any constraints are active.
30 */
31
32 /*
33 * Include necessary headers...
34 */
35
36 #include "ppd-private.h"
37 #include "string.h"
38 #include "debug.h"
39
40
41 /*
42 * Local constants...
43 */
44
45 enum
46 {
47 _PPD_NORMAL_CONSTRAINTS,
48 _PPD_INSTALLABLE_CONSTRAINTS,
49 _PPD_ALL_CONSTRAINTS
50 };
51
52
53 /*
54 * Local functions...
55 */
56
57 static int ppd_is_installable(ppd_group_t *installable,
58 const char *option);
59 static void ppd_load_constraints(ppd_file_t *ppd);
60 static cups_array_t *ppd_test_constraints(ppd_file_t *ppd,
61 const char *option,
62 const char *choice,
63 int num_options,
64 cups_option_t *options,
65 int which);
66
67
68 /*
69 * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD.
70 *
71 * This function attempts to resolve any conflicts in a marked PPD, returning
72 * a list of option changes that are required to resolve them. On input,
73 * "num_options" and "options" contain any pending option changes that have
74 * not yet been marked, while "option" and "choice" contain the most recent
75 * selection which may or may not be in "num_options" or "options".
76 *
77 * On successful return, "num_options" and "options" are updated to contain
78 * "option" and "choice" along with any changes required to resolve conflicts
79 * specified in the PPD file and 1 is returned.
80 *
81 * If option conflicts cannot be resolved, "num_options" and "options" are not
82 * changed and 0 is returned.
83 *
84 * When resolving conflicts, @code cupsResolveConflicts@ does not consider
85 * changes to the current page size (@code media@, @code PageSize@, and
86 * @code PageRegion@) or to the most recent option specified in "option".
87 * Thus, if the only way to resolve a conflict is to change the page size
88 * or the option the user most recently changed, @code cupsResolveConflicts@
89 * will return 0 to indicate it was unable to resolve the conflicts.
90 *
91 * The @code cupsResolveConflicts@ function uses one of two sources of option
92 * constraint information. The preferred constraint information is defined by
93 * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this
94 * case, the PPD file provides constraint resolution actions.
95 *
96 * The backup constraint information is defined by the
97 * @code UIConstraints@ and @code NonUIConstraints@ attributes. These
98 * constraints are resolved algorithmically by first selecting the default
99 * choice for the conflicting option, then iterating over all possible choices
100 * until a non-conflicting option choice is found.
101 *
102 * @since CUPS 1.4@
103 */
104
105 int /* O - 1 on success, 0 on failure */
106 cupsResolveConflicts(
107 ppd_file_t *ppd, /* I - PPD file */
108 const char *option, /* I - Newly selected option or @code NULL@ for none */
109 const char *choice, /* I - Newly selected choice or @code NULL@ for none */
110 int *num_options, /* IO - Number of additional selected options */
111 cups_option_t **options) /* IO - Additional selected options */
112 {
113 int i, /* Looping var */
114 num_newopts, /* Number of new options */
115 num_resopts; /* Number of resolver options */
116 cups_option_t *newopts, /* New options */
117 *resopts; /* Resolver options */
118 cups_array_t *active, /* Active constraints */
119 *pass, /* Resolvers for this pass */
120 *resolvers; /* Resolvers we have used */
121 _ppd_cups_uiconsts_t *consts; /* Current constraints */
122 _ppd_cups_uiconst_t *constptr; /* Current constraint */
123 ppd_attr_t *resolver; /* Current resolver */
124 const char *value; /* Selected option value */
125 int changed; /* Did we change anything? */
126 ppd_choice_t *marked; /* Marked choice */
127
128
129 /*
130 * Range check input...
131 */
132
133 if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL))
134 return (0);
135
136 /*
137 * Build a shadow option array...
138 */
139
140 num_newopts = 0;
141 newopts = NULL;
142
143 for (i = 0; i < *num_options; i ++)
144 num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value,
145 num_newopts, &newopts);
146 if (option && strcasecmp(option, "Collate"))
147 num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
148
149 /*
150 * Loop until we have no conflicts...
151 */
152
153 cupsArraySave(ppd->sorted_attrs);
154
155 resolvers = NULL;
156 pass = cupsArrayNew((cups_array_func_t)strcasecmp, NULL);
157
158 while ((active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts,
159 _PPD_ALL_CONSTRAINTS)) != NULL)
160 {
161 if (!resolvers)
162 resolvers = cupsArrayNew((cups_array_func_t)strcasecmp, NULL);
163
164 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0;
165 consts;
166 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
167 {
168 if (consts->resolver[0])
169 {
170 /*
171 * Look up the resolver...
172 */
173
174 if (cupsArrayFind(pass, consts->resolver))
175 continue; /* Already applied this resolver... */
176
177 if (cupsArrayFind(resolvers, consts->resolver))
178 {
179 /*
180 * Resolver loop!
181 */
182
183 DEBUG_printf(("ppdResolveConflicts: Resolver loop with %s!\n",
184 consts->resolver));
185 goto error;
186 }
187
188 if ((resolver = ppdFindAttr(ppd, "cupsUIResolver",
189 consts->resolver)) == NULL)
190 {
191 DEBUG_printf(("ppdResolveConflicts: Resolver %s not found!\n",
192 consts->resolver));
193 goto error;
194 }
195
196 if (!resolver->value)
197 {
198 DEBUG_printf(("ppdResolveConflicts: Resolver %s has no value!\n",
199 consts->resolver));
200 goto error;
201 }
202
203 /*
204 * Add the options from the resolver...
205 */
206
207 cupsArrayAdd(pass, consts->resolver);
208 cupsArrayAdd(resolvers, consts->resolver);
209
210 if (option && choice)
211 {
212 resopts = NULL;
213 num_resopts = _ppdParseOptions(resolver->value, 0, &resopts);
214
215 if ((value = cupsGetOption(option, num_newopts, newopts)) != NULL &&
216 !strcasecmp(value, choice))
217 {
218 DEBUG_printf(("cupsResolveConflicts: Resolver %s changes %s!\n",
219 consts->resolver, option));
220 cupsFreeOptions(num_resopts, resopts);
221 goto error;
222 }
223
224 cupsFreeOptions(num_resopts, resopts);
225 }
226
227 num_newopts = _ppdParseOptions(resolver->value, num_newopts, &newopts);
228 changed = 1;
229 }
230 else
231 {
232 /*
233 * Try resolving by choosing the default values for non-installable
234 * options, then by iterating through the possible choices...
235 */
236
237 int j; /* Looping var */
238 ppd_choice_t *cptr; /* Current choice */
239 cups_array_t *test; /* Test array for conflicts */
240
241
242 for (i = consts->num_constraints, constptr = consts->constraints;
243 i > 0 && !changed;
244 i --, constptr ++)
245 {
246 /*
247 * Can't resolve by changing an installable option...
248 */
249
250 if (constptr->installable)
251 continue;
252
253 /*
254 * Is this the option we are changing?
255 */
256
257 if (option && !strcasecmp(constptr->option->keyword, option))
258 continue;
259
260 /*
261 * Get the current option choice...
262 */
263
264 if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
265 newopts)) == NULL)
266 {
267 marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
268 value = marked ? marked->choice : "";
269 }
270
271 /*
272 * Try the default choice...
273 */
274
275 test = NULL;
276
277 if (strcasecmp(value, constptr->option->defchoice) &&
278 (test = ppd_test_constraints(ppd, constptr->option->keyword,
279 constptr->option->defchoice,
280 num_newopts, newopts,
281 _PPD_ALL_CONSTRAINTS)) == NULL)
282 {
283 /*
284 * That worked...
285 */
286
287 num_newopts = cupsAddOption(constptr->option->keyword,
288 constptr->option->defchoice,
289 num_newopts, &newopts);
290 changed = 1;
291 }
292 else
293 {
294 /*
295 * Try each choice instead...
296 */
297
298 for (j = constptr->option->num_choices,
299 cptr = constptr->option->choices;
300 j > 0;
301 j --, cptr ++)
302 {
303 cupsArrayDelete(test);
304 test = NULL;
305
306 if (strcasecmp(value, cptr->choice) &&
307 strcasecmp(constptr->option->defchoice, cptr->choice) &&
308 (test = ppd_test_constraints(ppd, constptr->option->keyword,
309 cptr->choice, num_newopts,
310 newopts,
311 _PPD_ALL_CONSTRAINTS)) == NULL)
312 {
313 /*
314 * This choice works...
315 */
316
317 num_newopts = cupsAddOption(constptr->option->keyword,
318 cptr->choice, num_newopts,
319 &newopts);
320 changed = 1;
321 break;
322 }
323 }
324
325 cupsArrayDelete(test);
326 }
327 }
328 }
329
330 if (!changed)
331 {
332 DEBUG_puts("ppdResolveConflicts: Unable to automatically resolve "
333 "constraint!");
334 goto error;
335 }
336 }
337
338 cupsArrayClear(pass);
339 cupsArrayDelete(active);
340 }
341
342 /*
343 * Free the caller's option array...
344 */
345
346 cupsFreeOptions(*num_options, *options);
347
348 /*
349 * If Collate is the option we are testing, add it here. Otherwise, remove
350 * any Collate option from the resolve list since the filters automatically
351 * handle manual collation...
352 */
353
354 if (option && !strcasecmp(option, "Collate"))
355 num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
356 else
357 num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
358
359 /*
360 * Return the new list of options to the caller...
361 */
362
363 *num_options = num_newopts;
364 *options = newopts;
365
366 cupsArrayDelete(pass);
367 cupsArrayDelete(resolvers);
368
369 cupsArrayRestore(ppd->sorted_attrs);
370
371 return (1);
372
373 /*
374 * If we get here, we failed to resolve...
375 */
376
377 error:
378
379 cupsFreeOptions(num_newopts, newopts);
380
381 cupsArrayDelete(pass);
382 cupsArrayDelete(resolvers);
383
384 cupsArrayRestore(ppd->sorted_attrs);
385
386 return (0);
387 }
388
389
390 /*
391 * 'ppdConflicts()' - Check to see if there are any conflicts among the
392 * marked option choices.
393 *
394 * The returned value is the same as returned by @link ppdMarkOption@.
395 */
396
397 int /* O - Number of conflicts found */
398 ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
399 {
400 int i, /* Looping variable */
401 conflicts; /* Number of conflicts */
402 cups_array_t *active; /* Active conflicts */
403 _ppd_cups_uiconsts_t *c; /* Current constraints */
404 _ppd_cups_uiconst_t *cptr; /* Current constraint */
405 ppd_option_t *o; /* Current option */
406
407
408 if (!ppd)
409 return (0);
410
411 /*
412 * Clear all conflicts...
413 */
414
415 for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
416 o->conflicted = 0;
417
418 /*
419 * Test for conflicts...
420 */
421
422 active = ppd_test_constraints(ppd, NULL, NULL, 0, NULL,
423 _PPD_ALL_CONSTRAINTS);
424 conflicts = cupsArrayCount(active);
425
426 /*
427 * Loop through all of the UI constraints and flag any options
428 * that conflict...
429 */
430
431 for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
432 c;
433 c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
434 {
435 for (i = c->num_constraints, cptr = c->constraints;
436 i > 0;
437 i --, cptr ++)
438 cptr->option->conflicted = 1;
439 }
440
441 cupsArrayDelete(active);
442
443 /*
444 * Return the number of conflicts found...
445 */
446
447 return (conflicts);
448 }
449
450
451 /*
452 * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
453 * an installable option.
454 *
455 * This function tests whether a particular option choice is available based
456 * on constraints against options in the "InstallableOptions" group.
457 *
458 * @since CUPS 1.4@
459 */
460
461 int /* O - 1 if conflicting, 0 if not conflicting */
462 ppdInstallableConflict(
463 ppd_file_t *ppd, /* I - PPD file */
464 const char *option, /* I - Option */
465 const char *choice) /* I - Choice */
466 {
467 cups_array_t *active; /* Active conflicts */
468
469
470 /*
471 * Range check input...
472 */
473
474 if (!ppd || !option || !choice)
475 return (0);
476
477 /*
478 * Test constraints using the new option...
479 */
480
481 active = ppd_test_constraints(ppd, option, choice, 0, NULL,
482 _PPD_INSTALLABLE_CONSTRAINTS);
483
484 cupsArrayDelete(active);
485
486 return (active != NULL);
487 }
488
489
490 /*
491 * 'ppd_is_installable()' - Determine whether an option is in the
492 * InstallableOptions group.
493 */
494
495 static int /* O - 1 if installable, 0 if normal */
496 ppd_is_installable(
497 ppd_group_t *installable, /* I - InstallableOptions group */
498 const char *name) /* I - Option name */
499 {
500 if (installable)
501 {
502 int i; /* Looping var */
503 ppd_option_t *option; /* Current option */
504
505
506 for (i = installable->num_options, option = installable->options;
507 i > 0;
508 i --, option ++)
509 if (!strcasecmp(option->keyword, name))
510 return (1);
511 }
512
513 return (0);
514 }
515
516
517 /*
518 * 'ppd_load_constraints()' - Load constraints from a PPD file.
519 */
520
521 static void
522 ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */
523 {
524 int i; /* Looping var */
525 ppd_const_t *oldconst; /* Current UIConstraints data */
526 ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
527 _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */
528 _ppd_cups_uiconst_t *constptr; /* Current constraint */
529 ppd_group_t *installable; /* Installable options group */
530 const char *vptr; /* Pointer into constraint value */
531 char option[PPD_MAX_NAME], /* Option name/MainKeyword */
532 choice[PPD_MAX_NAME], /* Choice/OptionKeyword */
533 *ptr; /* Pointer into option or choice */
534
535
536 /*
537 * Create an array to hold the constraint data...
538 */
539
540 ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL);
541
542 /*
543 * Find the installable options group if it exists...
544 */
545
546 for (i = ppd->num_groups, installable = ppd->groups;
547 i > 0;
548 i --, installable ++)
549 if (!strcasecmp(installable->name, "InstallableOptions"))
550 break;
551
552 if (i <= 0)
553 installable = NULL;
554
555 /*
556 * Load old-style [Non]UIConstraints data...
557 */
558
559 for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
560 {
561 /*
562 * Weed out nearby duplicates, since the PPD spec requires that you
563 * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
564 */
565
566 if (i > 1 &&
567 !strcasecmp(oldconst[0].option1, oldconst[1].option2) &&
568 !strcasecmp(oldconst[0].choice1, oldconst[1].choice2) &&
569 !strcasecmp(oldconst[0].option2, oldconst[1].option1) &&
570 !strcasecmp(oldconst[0].choice2, oldconst[1].choice1))
571 continue;
572
573 /*
574 * Allocate memory...
575 */
576
577 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
578 {
579 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
580 "UIConstraints!");
581 return;
582 }
583
584 if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
585 {
586 free(consts);
587 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
588 "UIConstraints!");
589 return;
590 }
591
592 /*
593 * Fill in the information...
594 */
595
596 consts->num_constraints = 2;
597 consts->constraints = constptr;
598
599 if (!strncasecmp(oldconst->option1, "Custom", 6) &&
600 !strcasecmp(oldconst->choice1, "True"))
601 {
602 constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6);
603 constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom");
604 constptr[0].installable = 0;
605 }
606 else
607 {
608 constptr[0].option = ppdFindOption(ppd, oldconst->option1);
609 constptr[0].choice = ppdFindChoice(constptr[0].option,
610 oldconst->choice1);
611 constptr[0].installable = ppd_is_installable(installable,
612 oldconst->option1);
613 }
614
615 if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
616 {
617 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
618 oldconst->option1, oldconst->choice1));
619 free(consts->constraints);
620 free(consts);
621 continue;
622 }
623
624 if (!strncasecmp(oldconst->option2, "Custom", 6) &&
625 !strcasecmp(oldconst->choice2, "True"))
626 {
627 constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6);
628 constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom");
629 constptr[1].installable = 0;
630 }
631 else
632 {
633 constptr[1].option = ppdFindOption(ppd, oldconst->option2);
634 constptr[1].choice = ppdFindChoice(constptr[1].option,
635 oldconst->choice2);
636 constptr[1].installable = ppd_is_installable(installable,
637 oldconst->option2);
638 }
639
640 if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
641 {
642 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
643 oldconst->option2, oldconst->choice2));
644 free(consts->constraints);
645 free(consts);
646 continue;
647 }
648
649 consts->installable = constptr[0].installable || constptr[1].installable;
650
651 /*
652 * Add it to the constraints array...
653 */
654
655 cupsArrayAdd(ppd->cups_uiconstraints, consts);
656 }
657
658 /*
659 * Then load new-style constraints...
660 */
661
662 for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL);
663 constattr;
664 constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
665 {
666 if (!constattr->value)
667 {
668 DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
669 continue;
670 }
671
672 for (i = 0, vptr = strchr(constattr->value, '*');
673 vptr;
674 i ++, vptr = strchr(vptr + 1, '*'));
675
676 if (i == 0)
677 {
678 DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
679 continue;
680 }
681
682 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
683 {
684 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
685 "cupsUIConstraints!");
686 return;
687 }
688
689 if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
690 {
691 free(consts);
692 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
693 "cupsUIConstraints!");
694 return;
695 }
696
697 consts->num_constraints = i;
698 consts->constraints = constptr;
699
700 strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
701
702 for (i = 0, vptr = strchr(constattr->value, '*');
703 vptr;
704 i ++, vptr = strchr(vptr, '*'), constptr ++)
705 {
706 /*
707 * Extract "*Option Choice" or just "*Option"...
708 */
709
710 for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
711 if (ptr < (option + sizeof(option) - 1))
712 *ptr++ = *vptr;
713
714 *ptr = '\0';
715
716 while (isspace(*vptr & 255))
717 vptr ++;
718
719 if (*vptr == '*')
720 choice[0] = '\0';
721 else
722 {
723 for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
724 if (ptr < (choice + sizeof(choice) - 1))
725 *ptr++ = *vptr;
726
727 *ptr = '\0';
728 }
729
730 if (!strncasecmp(option, "Custom", 6) && !strcasecmp(choice, "True"))
731 {
732 _cups_strcpy(option, option + 6);
733 strcpy(choice, "Custom");
734 }
735
736 constptr->option = ppdFindOption(ppd, option);
737 constptr->choice = ppdFindChoice(constptr->option, choice);
738 constptr->installable = ppd_is_installable(installable, option);
739 consts->installable |= constptr->installable;
740
741 if (!constptr->option || (!constptr->choice && choice[0]))
742 {
743 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
744 option, choice));
745 break;
746 }
747 }
748
749 if (!vptr)
750 cupsArrayAdd(ppd->cups_uiconstraints, consts);
751 else
752 {
753 free(consts->constraints);
754 free(consts);
755 }
756 }
757 }
758
759
760 /*
761 * 'ppd_test_constraints()' - See if any constraints are active.
762 */
763
764 static cups_array_t * /* O - Array of active constraints */
765 ppd_test_constraints(
766 ppd_file_t *ppd, /* I - PPD file */
767 const char *option, /* I - Current option */
768 const char *choice, /* I - Current choice */
769 int num_options, /* I - Number of additional options */
770 cups_option_t *options, /* I - Additional options */
771 int which) /* I - Which constraints to test */
772 {
773 int i; /* Looping var */
774 _ppd_cups_uiconsts_t *consts; /* Current constraints */
775 _ppd_cups_uiconst_t *constptr; /* Current constraint */
776 ppd_choice_t key, /* Search key */
777 *marked; /* Marked choice */
778 cups_array_t *active = NULL; /* Active constraints */
779 const char *value; /* Current value */
780 int option_conflict;/* Conflict with current option? */
781
782
783 DEBUG_printf(("ppd_test_constraints(ppd=%p, num_options=%d, options=%p, "
784 "which=%d)\n", ppd, num_options, options, which));
785
786 if (!ppd->cups_uiconstraints)
787 ppd_load_constraints(ppd);
788
789 DEBUG_printf(("ppd_test_constraints: %d constraints!\n",
790 cupsArrayCount(ppd->cups_uiconstraints)));
791
792 cupsArraySave(ppd->marked);
793
794 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
795 consts;
796 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
797 {
798 DEBUG_printf(("ppd_test_constraints: installable=%d, resolver=\"%s\", "
799 "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
800 "option2=\"%s\", choice2=\"%s\", ...\n",
801 consts->installable, consts->resolver, consts->num_constraints,
802 consts->constraints[0].option->keyword,
803 consts->constraints[0].choice ?
804 consts->constraints[0].choice->choice : "",
805 consts->constraints[1].option->keyword,
806 consts->constraints[1].choice ?
807 consts->constraints[1].choice->choice : ""));
808
809 if (which != _PPD_ALL_CONSTRAINTS && which != consts->installable)
810 continue;
811
812 DEBUG_puts("ppd_test_constraints: Testing...");
813
814 for (i = consts->num_constraints, constptr = consts->constraints,
815 option_conflict = 0;
816 i > 0;
817 i --, constptr ++)
818 {
819 DEBUG_printf(("ppd_test_constraints: %s=%s?\n", constptr->option->keyword,
820 constptr->choice ? constptr->choice->choice : ""));
821
822 if (constptr->choice &&
823 (!strcasecmp(constptr->option->keyword, "PageSize") ||
824 !strcasecmp(constptr->option->keyword, "PageRegion")))
825 {
826 /*
827 * PageSize and PageRegion are used depending on the selected input slot
828 * and manual feed mode. Validate against the selected page size instead
829 * of an individual option...
830 */
831
832 if (option && choice &&
833 (!strcasecmp(option, "PageSize") ||
834 !strcasecmp(option, "PageRegion")))
835 {
836 value = choice;
837
838 if (!strcasecmp(value, constptr->choice->choice))
839 option_conflict = 1;
840 }
841 else if ((value = cupsGetOption("PageSize", num_options,
842 options)) == NULL)
843 if ((value = cupsGetOption("PageRegion", num_options,
844 options)) == NULL)
845 if ((value = cupsGetOption("media", num_options, options)) == NULL)
846 {
847 ppd_size_t *size = ppdPageSize(ppd, NULL);
848
849 if (size)
850 value = size->name;
851 }
852
853 if (!value || strcasecmp(value, constptr->choice->choice))
854 {
855 DEBUG_puts("ppd_test_constraints: NO");
856 break;
857 }
858 }
859 else if (constptr->choice)
860 {
861 if (option && choice && !strcasecmp(option, constptr->option->keyword))
862 {
863 if (strcasecmp(choice, constptr->choice->choice))
864 break;
865
866 option_conflict = 1;
867 }
868 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
869 options)) != NULL)
870 {
871 if (strcasecmp(value, constptr->choice->choice))
872 {
873 DEBUG_puts("ppd_test_constraints: NO");
874 break;
875 }
876 }
877 else if (!constptr->choice->marked)
878 {
879 DEBUG_puts("ppd_test_constraints: NO");
880 break;
881 }
882 }
883 else if (option && choice &&
884 !strcasecmp(option, constptr->option->keyword))
885 {
886 if (!strcasecmp(choice, "None") || !strcasecmp(choice, "Off") ||
887 !strcasecmp(choice, "False"))
888 break;
889
890 option_conflict = 1;
891 }
892 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
893 options)) != NULL)
894 {
895 if (!strcasecmp(value, "None") || !strcasecmp(value, "Off") ||
896 !strcasecmp(value, "False"))
897 {
898 DEBUG_puts("ppd_test_constraints: NO");
899 break;
900 }
901 }
902 else
903 {
904 key.option = constptr->option;
905
906 if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key))
907 != NULL &&
908 (!strcasecmp(marked->choice, "None") ||
909 !strcasecmp(marked->choice, "Off") ||
910 !strcasecmp(marked->choice, "False")))
911 {
912 DEBUG_puts("ppd_test_constraints: NO");
913 break;
914 }
915 }
916 }
917
918 if (i <= 0 && (!option || option_conflict))
919 {
920 if (!active)
921 active = cupsArrayNew(NULL, NULL);
922
923 cupsArrayAdd(active, consts);
924 DEBUG_puts("ppd_test_constraints: Added...");
925 }
926 }
927
928 cupsArrayRestore(ppd->marked);
929
930 DEBUG_printf(("ppd_test_constraints: Found %d active constraints!\n",
931 cupsArrayCount(active)));
932
933 return (active);
934 }
935
936
937 /*
938 * End of "$Id$".
939 */