]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/conflicts.c
Merge changes from CUPS 1.4svn-r7874.
[thirdparty/cups.git] / cups / conflicts.c
CommitLineData
e78998df
MS
1/*
2 * "$Id$"
3 *
4 * Option marking routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 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 *
06d4e77b 21 * cupsResolveConflicts() - Resolve conflicts in a marked PPD.
e78998df
MS
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.
e78998df
MS
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
45enum
46{
47 _PPD_NORMAL_CONSTRAINTS,
48 _PPD_INSTALLABLE_CONSTRAINTS,
49 _PPD_ALL_CONSTRAINTS
50};
51
52
53/*
54 * Local functions...
55 */
56
57static int ppd_is_installable(ppd_group_t *installable,
58 const char *option);
59static void ppd_load_constraints(ppd_file_t *ppd);
06d4e77b
MS
60static cups_array_t *ppd_test_constraints(ppd_file_t *ppd,
61 const char *option,
62 const char *choice,
63 int num_options,
e78998df
MS
64 cups_option_t *options,
65 int which);
66
67
e78998df
MS
68/*
69 * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD.
70 *
71 * This function attempts to resolve any conflicts in a marked PPD, returning
06d4e77b
MS
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
e78998df
MS
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
06d4e77b
MS
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.
e78998df 83 *
06d4e77b
MS
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
e78998df 93 * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this
06d4e77b 94 * case, the PPD file provides constraint resolution actions.
e78998df 95 *
06d4e77b 96 * The backup constraint information is defined by the
e78998df 97 * @code UIConstraints@ and @code NonUIConstraints@ attributes. These
06d4e77b
MS
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.
e78998df
MS
101 *
102 * @since CUPS 1.4@
103 */
104
105int /* O - 1 on success, 0 on failure */
106cupsResolveConflicts(
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 */
06d4e77b
MS
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 */
e78998df
MS
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 */
e78998df
MS
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);
005dd1eb 146 if (option && strcasecmp(option, "Collate"))
e78998df
MS
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
06d4e77b 158 while ((active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts,
e78998df
MS
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
06d4e77b
MS
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
e78998df 227 num_newopts = _ppdParseOptions(resolver->value, num_newopts, &newopts);
06d4e77b 228 changed = 1;
e78998df
MS
229 }
230 else
231 {
232 /*
233 * Try resolving by choosing the default values for non-installable
06d4e77b 234 * options, then by iterating through the possible choices...
e78998df
MS
235 */
236
06d4e77b
MS
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;
e78998df
MS
243 i > 0;
244 i --, constptr ++)
245 {
246 if (constptr->installable ||
247 !strcasecmp(constptr->option->keyword, "PageSize") ||
248 !strcasecmp(constptr->option->keyword, "PageRegion"))
249 continue;
250
251 if (option && !strcasecmp(constptr->option->keyword, option))
e78998df 252 continue;
e78998df
MS
253
254 if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
255 newopts)) == NULL)
256 {
257 marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
258 value = marked ? marked->choice : "";
259 }
260
06d4e77b
MS
261 /*
262 * Try the default choice...
e78998df
MS
263 */
264
06d4e77b 265 test = NULL;
e78998df 266
06d4e77b
MS
267 if (strcasecmp(value, constptr->option->defchoice) &&
268 (test = ppd_test_constraints(ppd, constptr->option->keyword,
269 constptr->option->defchoice,
270 num_newopts, newopts,
271 _PPD_ALL_CONSTRAINTS)) == NULL)
e78998df 272 {
06d4e77b
MS
273 /*
274 * That worked...
275 */
276
277 num_newopts = cupsAddOption(constptr->option->keyword,
278 constptr->option->defchoice,
e78998df
MS
279 num_newopts, &newopts);
280 changed = 1;
281 }
06d4e77b
MS
282 else
283 {
284 /*
285 * Try each choice instead...
286 */
287
288 cupsArrayDelete(test);
289
290 for (j = constptr->option->num_choices,
291 cptr = constptr->option->choices;
292 j > 0;
293 j --, cptr ++)
294 {
295 test = NULL;
296
297 if (strcasecmp(value, cptr->choice) &&
298 strcasecmp(constptr->option->defchoice, cptr->choice) &&
299 (test = ppd_test_constraints(ppd, constptr->option->keyword,
300 cptr->choice, num_newopts,
301 newopts,
302 _PPD_ALL_CONSTRAINTS)) == NULL)
303 {
304 /*
305 * This choice works...
306 */
307
308 num_newopts = cupsAddOption(constptr->option->keyword,
309 cptr->choice, num_newopts,
310 &newopts);
311 changed = 1;
312 break;
313 }
314
315 cupsArrayDelete(test);
316 }
317 }
318 }
e78998df
MS
319 }
320
321 if (!changed)
322 {
323 DEBUG_puts("ppdResolveConflicts: Unable to automatically resolve "
324 "constraint!");
325 goto error;
326 }
327 }
328
329 cupsArrayClear(pass);
330 cupsArrayDelete(active);
331 }
332
333 /*
005dd1eb 334 * Free the caller's option array...
e78998df
MS
335 */
336
005dd1eb
MS
337 cupsFreeOptions(*num_options, *options);
338
339 /*
340 * If Collate is the option we are testing, add it here. Otherwise, remove
341 * any Collate option from the resolve list since the filters automatically
342 * handle manual collation...
343 */
344
345 if (option && !strcasecmp(option, "Collate"))
346 num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
e78998df 347 else
005dd1eb
MS
348 num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
349
350 /*
351 * Return the new list of options to the caller...
352 */
353
354 *num_options = num_newopts;
355 *options = newopts;
e78998df
MS
356
357 cupsArrayDelete(pass);
358 cupsArrayDelete(resolvers);
359
360 cupsArrayRestore(ppd->sorted_attrs);
361
362 return (1);
363
364 /*
365 * If we get here, we failed to resolve...
366 */
367
368 error:
369
370 cupsFreeOptions(num_newopts, newopts);
371
372 cupsArrayDelete(pass);
373 cupsArrayDelete(resolvers);
374
375 cupsArrayRestore(ppd->sorted_attrs);
376
377 return (0);
378}
379
380
06d4e77b
MS
381/*
382 * 'ppdConflicts()' - Check to see if there are any conflicts among the
383 * marked option choices.
384 *
385 * The returned value is the same as returned by @link ppdMarkOption@.
386 */
387
388int /* O - Number of conflicts found */
389ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
390{
391 int i, /* Looping variable */
392 conflicts; /* Number of conflicts */
393 cups_array_t *active; /* Active conflicts */
394 _ppd_cups_uiconsts_t *c; /* Current constraints */
395 _ppd_cups_uiconst_t *cptr; /* Current constraint */
396 ppd_option_t *o; /* Current option */
397
398
399 if (!ppd)
400 return (0);
401
402 /*
403 * Clear all conflicts...
404 */
405
406 for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
407 o->conflicted = 0;
408
409 /*
410 * Test for conflicts...
411 */
412
413 active = ppd_test_constraints(ppd, NULL, NULL, 0, NULL,
414 _PPD_ALL_CONSTRAINTS);
415 conflicts = cupsArrayCount(active);
416
417 /*
418 * Loop through all of the UI constraints and flag any options
419 * that conflict...
420 */
421
422 for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
423 c;
424 c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
425 {
426 for (i = c->num_constraints, cptr = c->constraints;
427 i > 0;
428 i --, cptr ++)
429 cptr->option->conflicted = 1;
430 }
431
432 cupsArrayDelete(active);
433
434 /*
435 * Return the number of conflicts found...
436 */
437
438 return (conflicts);
439}
440
441
442/*
443 * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
444 * an installable option.
445 *
446 * This function tests whether a particular option choice is available based
447 * on constraints against options in the "InstallableOptions" group.
448 *
449 * @since CUPS 1.4@
450 */
451
452int /* O - 1 if conflicting, 0 if not conflicting */
453ppdInstallableConflict(
454 ppd_file_t *ppd, /* I - PPD file */
455 const char *option, /* I - Option */
456 const char *choice) /* I - Choice */
457{
458 cups_array_t *active; /* Active conflicts */
459
460
461 /*
462 * Range check input...
463 */
464
465 if (!ppd || !option || !choice)
466 return (0);
467
468 /*
469 * Test constraints using the new option...
470 */
471
472 active = ppd_test_constraints(ppd, option, choice, 0, NULL,
473 _PPD_INSTALLABLE_CONSTRAINTS);
474
475 cupsArrayDelete(active);
476
477 return (active != NULL);
478}
479
480
e78998df
MS
481/*
482 * 'ppd_is_installable()' - Determine whether an option is in the
483 * InstallableOptions group.
484 */
485
486static int /* O - 1 if installable, 0 if normal */
487ppd_is_installable(
488 ppd_group_t *installable, /* I - InstallableOptions group */
489 const char *name) /* I - Option name */
490{
491 if (installable)
492 {
493 int i; /* Looping var */
494 ppd_option_t *option; /* Current option */
495
496
497 for (i = installable->num_options, option = installable->options;
498 i > 0;
499 i --, option ++)
500 if (!strcasecmp(option->keyword, name))
501 return (1);
502 }
503
504 return (0);
505}
506
507
508/*
509 * 'ppd_load_constraints()' - Load constraints from a PPD file.
510 */
511
512static void
513ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */
514{
515 int i; /* Looping var */
516 ppd_const_t *oldconst; /* Current UIConstraints data */
517 ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
518 _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */
519 _ppd_cups_uiconst_t *constptr; /* Current constraint */
520 ppd_group_t *installable; /* Installable options group */
521 const char *vptr; /* Pointer into constraint value */
522 char option[PPD_MAX_NAME], /* Option name/MainKeyword */
523 choice[PPD_MAX_NAME], /* Choice/OptionKeyword */
524 *ptr; /* Pointer into option or choice */
525
526
527 /*
528 * Create an array to hold the constraint data...
529 */
530
531 ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL);
532
533 /*
534 * Find the installable options group if it exists...
535 */
536
537 for (i = ppd->num_groups, installable = ppd->groups;
538 i > 0;
539 i --, installable ++)
540 if (!strcasecmp(installable->name, "InstallableOptions"))
541 break;
542
543 if (i <= 0)
544 installable = NULL;
545
546 /*
547 * See what kind of constraint data we have in the PPD...
548 */
549
550 if ((constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL)) != NULL)
551 {
552 /*
553 * Load new-style cupsUIConstraints data...
554 */
555
556 for (; constattr;
557 constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
558 {
559 if (!constattr->value)
560 {
561 DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
562 continue;
563 }
564
565 for (i = 0, vptr = strchr(constattr->value, '*');
566 vptr;
567 i ++, vptr = strchr(vptr + 1, '*'));
568
569 if (i == 0)
570 {
571 DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
572 continue;
573 }
574
575 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
576 {
577 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
578 "cupsUIConstraints!");
579 return;
580 }
581
582 if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
583 {
584 free(consts);
585 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
586 "cupsUIConstraints!");
587 return;
588 }
589
590 consts->num_constraints = i;
591 consts->constraints = constptr;
592
593 strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
594
595 for (i = 0, vptr = strchr(constattr->value, '*');
596 vptr;
005dd1eb 597 i ++, vptr = strchr(vptr, '*'), constptr ++)
e78998df
MS
598 {
599 /*
600 * Extract "*Option Choice" or just "*Option"...
601 */
602
603 for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
604 if (ptr < (option + sizeof(option) - 1))
605 *ptr++ = *vptr;
606
607 *ptr = '\0';
608
609 while (isspace(*vptr & 255))
610 vptr ++;
611
612 if (*vptr == '*')
e78998df 613 choice[0] = '\0';
e78998df
MS
614 else
615 {
616 for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
617 if (ptr < (choice + sizeof(choice) - 1))
618 *ptr++ = *vptr;
619
620 *ptr = '\0';
621 }
622
623 if (!strncasecmp(option, "Custom", 6) && !strcasecmp(choice, "True"))
624 {
625 _cups_strcpy(option, option + 6);
626 strcpy(choice, "Custom");
627 }
628
629 constptr->option = ppdFindOption(ppd, option);
630 constptr->choice = ppdFindChoice(constptr->option, choice);
631 constptr->installable = ppd_is_installable(installable, option);
632 consts->installable |= constptr->installable;
633
005dd1eb 634 if (!constptr->option || (!constptr->choice && choice[0]))
e78998df 635 {
005dd1eb
MS
636 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
637 option, choice));
e78998df
MS
638 break;
639 }
640 }
641
642 if (!vptr)
643 cupsArrayAdd(ppd->cups_uiconstraints, consts);
644 else
645 {
646 free(consts->constraints);
647 free(consts);
648 }
649 }
650 }
651 else
652 {
653 /*
654 * Load old-style [Non]UIConstraints data...
655 */
656
657 for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
658 {
659 /*
660 * Weed out nearby duplicates, since the PPD spec requires that you
661 * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
662 */
663
664 if (i > 1 &&
665 !strcasecmp(oldconst[0].option1, oldconst[1].option2) &&
666 !strcasecmp(oldconst[0].choice1, oldconst[1].choice2) &&
667 !strcasecmp(oldconst[0].option2, oldconst[1].option1) &&
668 !strcasecmp(oldconst[0].choice2, oldconst[1].choice1))
669 continue;
670
671 /*
672 * Allocate memory...
673 */
674
675 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
676 {
677 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
678 "UIConstraints!");
679 return;
680 }
681
682 if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
683 {
684 free(consts);
685 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
686 "UIConstraints!");
687 return;
688 }
689
690 /*
691 * Fill in the information...
692 */
693
694 consts->num_constraints = 2;
695 consts->constraints = constptr;
696
697 if (!strncasecmp(oldconst->option1, "Custom", 6) &&
698 !strcasecmp(oldconst->choice1, "True"))
699 {
700 constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6);
701 constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom");
702 constptr[0].installable = 0;
703 }
704 else
705 {
706 constptr[0].option = ppdFindOption(ppd, oldconst->option1);
707 constptr[0].choice = ppdFindChoice(constptr[0].option,
708 oldconst->choice1);
709 constptr[0].installable = ppd_is_installable(installable,
710 oldconst->option1);
711 }
712
005dd1eb 713 if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
e78998df 714 {
005dd1eb
MS
715 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
716 oldconst->option1, oldconst->choice1));
e78998df
MS
717 free(consts->constraints);
718 free(consts);
719 continue;
720 }
721
722 if (!strncasecmp(oldconst->option2, "Custom", 6) &&
723 !strcasecmp(oldconst->choice2, "True"))
724 {
725 constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6);
726 constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom");
727 constptr[1].installable = 0;
728 }
729 else
730 {
731 constptr[1].option = ppdFindOption(ppd, oldconst->option2);
732 constptr[1].choice = ppdFindChoice(constptr[1].option,
733 oldconst->choice2);
734 constptr[1].installable = ppd_is_installable(installable,
735 oldconst->option2);
736 }
737
005dd1eb 738 if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
e78998df 739 {
005dd1eb
MS
740 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
741 oldconst->option2, oldconst->choice2));
e78998df
MS
742 free(consts->constraints);
743 free(consts);
744 continue;
745 }
746
747 consts->installable = constptr[0].installable || constptr[1].installable;
748
749 /*
750 * Add it to the constraints array...
751 */
752
753 cupsArrayAdd(ppd->cups_uiconstraints, consts);
754 }
755 }
756}
757
758
e78998df
MS
759/*
760 * 'ppd_test_constraints()' - See if any constraints are active.
761 */
762
763static cups_array_t * /* O - Array of active constraints */
764ppd_test_constraints(
765 ppd_file_t *ppd, /* I - PPD file */
06d4e77b
MS
766 const char *option, /* I - Current option */
767 const char *choice, /* I - Current choice */
e78998df
MS
768 int num_options, /* I - Number of additional options */
769 cups_option_t *options, /* I - Additional options */
770 int which) /* I - Which constraints to test */
771{
772 int i; /* Looping var */
773 _ppd_cups_uiconsts_t *consts; /* Current constraints */
774 _ppd_cups_uiconst_t *constptr; /* Current constraint */
775 ppd_choice_t key, /* Search key */
776 *marked; /* Marked choice */
777 cups_array_t *active = NULL; /* Active constraints */
778 const char *value; /* Current value */
06d4e77b
MS
779 int option_conflict;/* Conflict with current option? */
780
e78998df 781
06d4e77b
MS
782 DEBUG_printf(("ppd_test_constraints(ppd=%p, num_options=%d, options=%p, "
783 "which=%d)\n", ppd, num_options, options, which));
e78998df
MS
784
785 if (!ppd->cups_uiconstraints)
786 ppd_load_constraints(ppd);
787
06d4e77b
MS
788 DEBUG_printf(("ppd_test_constraints: %d constraints!\n",
789 cupsArrayCount(ppd->cups_uiconstraints)));
790
e78998df
MS
791 cupsArraySave(ppd->marked);
792
793 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
794 consts;
795 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
796 {
06d4e77b
MS
797 DEBUG_printf(("ppd_test_constraints: installable=%d, resolver=\"%s\", "
798 "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
799 "option2=\"%s\", choice2=\"%s\", ...\n",
800 consts->installable, consts->resolver, consts->num_constraints,
801 consts->constraints[0].option->keyword,
802 consts->constraints[0].choice ?
803 consts->constraints[0].choice->choice : "",
804 consts->constraints[1].option->keyword,
805 consts->constraints[1].choice ?
806 consts->constraints[1].choice->choice : ""));
807
e78998df
MS
808 if (which != _PPD_ALL_CONSTRAINTS && which != consts->installable)
809 continue;
810
06d4e77b
MS
811 DEBUG_puts("ppd_test_constraints: Testing...");
812
813 for (i = consts->num_constraints, constptr = consts->constraints,
814 option_conflict = 0;
e78998df
MS
815 i > 0;
816 i --, constptr ++)
817 {
06d4e77b
MS
818 DEBUG_printf(("ppd_test_constraints: %s=%s?\n", constptr->option->keyword,
819 constptr->choice ? constptr->choice->choice : ""));
820
e78998df
MS
821 if (constptr->choice &&
822 (!strcasecmp(constptr->option->keyword, "PageSize") ||
823 !strcasecmp(constptr->option->keyword, "PageRegion")))
824 {
825 /*
826 * PageSize and PageRegion are used depending on the selected input slot
827 * and manual feed mode. Validate against the selected page size instead
828 * of an individual option...
829 */
830
06d4e77b
MS
831 if (option && choice &&
832 (!strcasecmp(option, "PageSize") ||
833 !strcasecmp(option, "PageRegion")))
834 {
835 value = choice;
836
837 if (!strcasecmp(value, constptr->choice->choice))
838 option_conflict = 1;
839 }
840 else if ((value = cupsGetOption("PageSize", num_options,
841 options)) == NULL)
e78998df
MS
842 if ((value = cupsGetOption("PageRegion", num_options,
843 options)) == NULL)
844 if ((value = cupsGetOption("media", num_options, options)) == NULL)
845 {
846 ppd_size_t *size = ppdPageSize(ppd, NULL);
847
848 if (size)
849 value = size->name;
850 }
851
852 if (!value || strcasecmp(value, constptr->choice->choice))
06d4e77b
MS
853 {
854 DEBUG_puts("ppd_test_constraints: NO");
e78998df 855 break;
06d4e77b 856 }
e78998df
MS
857 }
858 else if (constptr->choice)
859 {
06d4e77b
MS
860 if (option && choice && !strcasecmp(option, constptr->option->keyword))
861 {
862 if (strcasecmp(choice, constptr->choice->choice))
863 break;
864
865 option_conflict = 1;
866 }
867 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
868 options)) != NULL)
e78998df
MS
869 {
870 if (strcasecmp(value, constptr->choice->choice))
06d4e77b
MS
871 {
872 DEBUG_puts("ppd_test_constraints: NO");
e78998df 873 break;
06d4e77b 874 }
e78998df
MS
875 }
876 else if (!constptr->choice->marked)
06d4e77b
MS
877 {
878 DEBUG_puts("ppd_test_constraints: NO");
879 break;
880 }
881 }
882 else if (option && choice &&
883 !strcasecmp(option, constptr->option->keyword))
884 {
885 if (!strcasecmp(choice, "None") || !strcasecmp(choice, "Off") ||
886 !strcasecmp(choice, "False"))
e78998df 887 break;
06d4e77b
MS
888
889 option_conflict = 1;
e78998df
MS
890 }
891 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
892 options)) != NULL)
893 {
894 if (!strcasecmp(value, "None") || !strcasecmp(value, "Off") ||
895 !strcasecmp(value, "False"))
06d4e77b
MS
896 {
897 DEBUG_puts("ppd_test_constraints: NO");
898 break;
899 }
e78998df
MS
900 }
901 else
902 {
903 key.option = constptr->option;
904
905 if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key))
906 != NULL &&
907 (!strcasecmp(marked->choice, "None") ||
908 !strcasecmp(marked->choice, "Off") ||
909 !strcasecmp(marked->choice, "False")))
06d4e77b
MS
910 {
911 DEBUG_puts("ppd_test_constraints: NO");
e78998df 912 break;
06d4e77b 913 }
e78998df
MS
914 }
915 }
916
06d4e77b 917 if (i <= 0 && (!option || option_conflict))
e78998df
MS
918 {
919 if (!active)
920 active = cupsArrayNew(NULL, NULL);
921
922 cupsArrayAdd(active, consts);
06d4e77b 923 DEBUG_puts("ppd_test_constraints: Added...");
e78998df
MS
924 }
925 }
926
927 cupsArrayRestore(ppd->marked);
928
06d4e77b
MS
929 DEBUG_printf(("ppd_test_constraints: Found %d active constraints!\n",
930 cupsArrayCount(active)));
931
e78998df
MS
932 return (active);
933}
934
935
936/*
937 * End of "$Id$".
938 */