]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/conflicts.c
Import CUPS v1.7.1
[thirdparty/cups.git] / cups / conflicts.c
1 /*
2 * "$Id: conflicts.c 3933 2012-10-01 03:01:10Z msweet $"
3 *
4 * Option marking routines for CUPS.
5 *
6 * Copyright 2007-2012 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 * cupsGetConflicts() - Get a list of conflicting options in a marked
22 * PPD.
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
27 * installable option.
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.
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "cups-private.h"
39 #include "ppd-private.h"
40
41
42 /*
43 * Local constants...
44 */
45
46 enum
47 {
48 _PPD_NORMAL_CONSTRAINTS,
49 _PPD_OPTION_CONSTRAINTS,
50 _PPD_INSTALLABLE_CONSTRAINTS,
51 _PPD_ALL_CONSTRAINTS
52 };
53
54
55 /*
56 * Local functions...
57 */
58
59 static int ppd_is_installable(ppd_group_t *installable,
60 const char *option);
61 static void ppd_load_constraints(ppd_file_t *ppd);
62 static cups_array_t *ppd_test_constraints(ppd_file_t *ppd,
63 const char *option,
64 const char *choice,
65 int num_options,
66 cups_option_t *options,
67 int which);
68
69
70 /*
71 * 'cupsGetConflicts()' - Get a list of conflicting options in a marked PPD.
72 *
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.
77 *
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@.
81 *
82 * @since CUPS 1.4/OS X 10.6@
83 */
84
85 int /* O - Number of conflicting options */
86 cupsGetConflicts(
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 */
91 {
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 */
98
99
100 /*
101 * Range check input...
102 */
103
104 if (options)
105 *options = NULL;
106
107 if (!ppd || !option || !choice || !options)
108 return (0);
109
110 /*
111 * Test for conflicts...
112 */
113
114 active = ppd_test_constraints(ppd, option, choice, 0, NULL,
115 _PPD_ALL_CONSTRAINTS);
116
117 /*
118 * Loop through all of the UI constraints and add any options that conflict...
119 */
120
121 for (num_options = 0, c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
122 c;
123 c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
124 {
125 for (i = c->num_constraints, cptr = c->constraints;
126 i > 0;
127 i --, cptr ++)
128 if (_cups_strcasecmp(cptr->option->keyword, option))
129 {
130 if (cptr->choice)
131 num_options = cupsAddOption(cptr->option->keyword,
132 cptr->choice->choice, num_options,
133 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);
138 }
139 }
140
141 cupsArrayDelete(active);
142
143 return (num_options);
144 }
145
146
147 /*
148 * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD.
149 *
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".
155 *
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.
159 *
160 * If option conflicts cannot be resolved, "num_options" and "options" are not
161 * changed and 0 is returned.
162 *
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.
169 *
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.
174 *
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.
180 *
181 * @since CUPS 1.4/OS X 10.6@
182 */
183
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 */
191 {
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 */
213
214
215 /*
216 * Range check input...
217 */
218
219 if (!ppd || !num_options || !options || (option == NULL) != (choice == NULL))
220 return (0);
221
222 /*
223 * Build a shadow option array...
224 */
225
226 num_newopts = 0;
227 newopts = NULL;
228
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);
234
235 /*
236 * Loop until we have no conflicts...
237 */
238
239 cupsArraySave(ppd->sorted_attrs);
240
241 resolvers = NULL;
242 pass = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
243 tries = 0;
244
245 while (tries < 100 &&
246 (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts,
247 _PPD_ALL_CONSTRAINTS)) != NULL)
248 {
249 tries ++;
250
251 if (!resolvers)
252 resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL);
253
254 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0;
255 consts;
256 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
257 {
258 if (consts->resolver[0])
259 {
260 /*
261 * Look up the resolver...
262 */
263
264 if (cupsArrayFind(pass, consts->resolver))
265 continue; /* Already applied this resolver... */
266
267 if (cupsArrayFind(resolvers, consts->resolver))
268 {
269 /*
270 * Resolver loop!
271 */
272
273 DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!",
274 consts->resolver));
275 goto error;
276 }
277
278 if ((resolver = ppdFindAttr(ppd, "cupsUIResolver",
279 consts->resolver)) == NULL)
280 {
281 DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!",
282 consts->resolver));
283 goto error;
284 }
285
286 if (!resolver->value)
287 {
288 DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!",
289 consts->resolver));
290 goto error;
291 }
292
293 /*
294 * Add the options from the resolver...
295 */
296
297 cupsArrayAdd(pass, consts->resolver);
298 cupsArrayAdd(resolvers, consts->resolver);
299
300 for (resval = resolver->value; *resval && !changed;)
301 {
302 while (_cups_isspace(*resval))
303 resval ++;
304
305 if (*resval != '*')
306 break;
307
308 for (resval ++, resptr = resoption;
309 *resval && !_cups_isspace(*resval);
310 resval ++)
311 if (resptr < (resoption + sizeof(resoption) - 1))
312 *resptr++ = *resval;
313
314 *resptr = '\0';
315
316 while (_cups_isspace(*resval))
317 resval ++;
318
319 for (resptr = reschoice;
320 *resval && !_cups_isspace(*resval);
321 resval ++)
322 if (resptr < (reschoice + sizeof(reschoice) - 1))
323 *resptr++ = *resval;
324
325 *resptr = '\0';
326
327 if (!resoption[0] || !reschoice[0])
328 break;
329
330 /*
331 * Is this the option we are changing?
332 */
333
334 snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption);
335
336 if (option &&
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"))))
351 continue;
352
353 /*
354 * Try this choice...
355 */
356
357 if ((test = ppd_test_constraints(ppd, resoption, reschoice,
358 num_newopts, newopts,
359 _PPD_ALL_CONSTRAINTS)) == NULL)
360 {
361 /*
362 * That worked...
363 */
364
365 changed = 1;
366 }
367 else
368 cupsArrayDelete(test);
369
370 /*
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...
374 */
375
376 num_newopts = cupsAddOption(resoption, reschoice, num_newopts,
377 &newopts);
378 }
379 }
380 else
381 {
382 /*
383 * Try resolving by choosing the default values for non-installable
384 * options, then by iterating through the possible choices...
385 */
386
387 int j; /* Looping var */
388 ppd_choice_t *cptr; /* Current choice */
389 ppd_size_t *size; /* Current page size */
390
391
392 for (i = consts->num_constraints, constptr = consts->constraints;
393 i > 0 && !changed;
394 i --, constptr ++)
395 {
396 /*
397 * Can't resolve by changing an installable option...
398 */
399
400 if (constptr->installable)
401 continue;
402
403 /*
404 * Is this the option we are changing?
405 */
406
407 if (option &&
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"))))
413 continue;
414
415 /*
416 * Get the current option choice...
417 */
418
419 if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
420 newopts)) == NULL)
421 {
422 if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
423 !_cups_strcasecmp(constptr->option->keyword, "PageRegion"))
424 {
425 if ((value = cupsGetOption("PageSize", num_newopts,
426 newopts)) == NULL)
427 value = cupsGetOption("PageRegion", num_newopts, newopts);
428
429 if (!value)
430 {
431 if ((size = ppdPageSize(ppd, NULL)) != NULL)
432 value = size->name;
433 else
434 value = "";
435 }
436 }
437 else
438 {
439 marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
440 value = marked ? marked->choice : "";
441 }
442 }
443
444 if (!_cups_strncasecmp(value, "Custom.", 7))
445 value = "Custom";
446
447 /*
448 * Try the default choice...
449 */
450
451 test = NULL;
452
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)
458 {
459 /*
460 * That worked...
461 */
462
463 num_newopts = cupsAddOption(constptr->option->keyword,
464 constptr->option->defchoice,
465 num_newopts, &newopts);
466 changed = 1;
467 }
468 else
469 {
470 /*
471 * Try each choice instead...
472 */
473
474 for (j = constptr->option->num_choices,
475 cptr = constptr->option->choices;
476 j > 0;
477 j --, cptr ++)
478 {
479 cupsArrayDelete(test);
480 test = NULL;
481
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,
487 newopts,
488 _PPD_OPTION_CONSTRAINTS)) == NULL)
489 {
490 /*
491 * This choice works...
492 */
493
494 num_newopts = cupsAddOption(constptr->option->keyword,
495 cptr->choice, num_newopts,
496 &newopts);
497 changed = 1;
498 break;
499 }
500 }
501
502 cupsArrayDelete(test);
503 }
504 }
505 }
506 }
507
508 if (!changed)
509 {
510 DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve "
511 "constraint!");
512 goto error;
513 }
514
515 cupsArrayClear(pass);
516 cupsArrayDelete(active);
517 active = NULL;
518 }
519
520 if (tries >= 100)
521 goto error;
522
523 /*
524 * Free the caller's option array...
525 */
526
527 cupsFreeOptions(*num_options, *options);
528
529 /*
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...
533 */
534
535 if (option && !_cups_strcasecmp(option, "Collate"))
536 num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
537 else
538 num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
539
540 /*
541 * Return the new list of options to the caller...
542 */
543
544 *num_options = num_newopts;
545 *options = newopts;
546
547 cupsArrayDelete(pass);
548 cupsArrayDelete(resolvers);
549
550 cupsArrayRestore(ppd->sorted_attrs);
551
552 DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts));
553 #ifdef DEBUG
554 for (i = 0; i < num_newopts; i ++)
555 DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i,
556 newopts[i].name, newopts[i].value));
557 #endif /* DEBUG */
558
559 return (1);
560
561 /*
562 * If we get here, we failed to resolve...
563 */
564
565 error:
566
567 cupsFreeOptions(num_newopts, newopts);
568
569 cupsArrayDelete(active);
570 cupsArrayDelete(pass);
571 cupsArrayDelete(resolvers);
572
573 cupsArrayRestore(ppd->sorted_attrs);
574
575 DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!");
576
577 return (0);
578 }
579
580
581 /*
582 * 'ppdConflicts()' - Check to see if there are any conflicts among the
583 * marked option choices.
584 *
585 * The returned value is the same as returned by @link ppdMarkOption@.
586 */
587
588 int /* O - Number of conflicts found */
589 ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
590 {
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 */
597
598
599 if (!ppd)
600 return (0);
601
602 /*
603 * Clear all conflicts...
604 */
605
606 cupsArraySave(ppd->options);
607
608 for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
609 o->conflicted = 0;
610
611 cupsArrayRestore(ppd->options);
612
613 /*
614 * Test for conflicts...
615 */
616
617 active = ppd_test_constraints(ppd, NULL, NULL, 0, NULL,
618 _PPD_ALL_CONSTRAINTS);
619 conflicts = cupsArrayCount(active);
620
621 /*
622 * Loop through all of the UI constraints and flag any options
623 * that conflict...
624 */
625
626 for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
627 c;
628 c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
629 {
630 for (i = c->num_constraints, cptr = c->constraints;
631 i > 0;
632 i --, cptr ++)
633 cptr->option->conflicted = 1;
634 }
635
636 cupsArrayDelete(active);
637
638 /*
639 * Return the number of conflicts found...
640 */
641
642 return (conflicts);
643 }
644
645
646 /*
647 * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
648 * an installable option.
649 *
650 * This function tests whether a particular option choice is available based
651 * on constraints against options in the "InstallableOptions" group.
652 *
653 * @since CUPS 1.4/OS X 10.6@
654 */
655
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 */
661 {
662 cups_array_t *active; /* Active conflicts */
663
664
665 DEBUG_printf(("2ppdInstallableConflict(ppd=%p, option=\"%s\", choice=\"%s\")",
666 ppd, option, choice));
667
668 /*
669 * Range check input...
670 */
671
672 if (!ppd || !option || !choice)
673 return (0);
674
675 /*
676 * Test constraints using the new option...
677 */
678
679 active = ppd_test_constraints(ppd, option, choice, 0, NULL,
680 _PPD_INSTALLABLE_CONSTRAINTS);
681
682 cupsArrayDelete(active);
683
684 return (active != NULL);
685 }
686
687
688 /*
689 * 'ppd_is_installable()' - Determine whether an option is in the
690 * InstallableOptions group.
691 */
692
693 static int /* O - 1 if installable, 0 if normal */
694 ppd_is_installable(
695 ppd_group_t *installable, /* I - InstallableOptions group */
696 const char *name) /* I - Option name */
697 {
698 if (installable)
699 {
700 int i; /* Looping var */
701 ppd_option_t *option; /* Current option */
702
703
704 for (i = installable->num_options, option = installable->options;
705 i > 0;
706 i --, option ++)
707 if (!_cups_strcasecmp(option->keyword, name))
708 return (1);
709 }
710
711 return (0);
712 }
713
714
715 /*
716 * 'ppd_load_constraints()' - Load constraints from a PPD file.
717 */
718
719 static void
720 ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */
721 {
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 */
732
733
734 DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd));
735
736 /*
737 * Create an array to hold the constraint data...
738 */
739
740 ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL);
741
742 /*
743 * Find the installable options group if it exists...
744 */
745
746 for (i = ppd->num_groups, installable = ppd->groups;
747 i > 0;
748 i --, installable ++)
749 if (!_cups_strcasecmp(installable->name, "InstallableOptions"))
750 break;
751
752 if (i <= 0)
753 installable = NULL;
754
755 /*
756 * Load old-style [Non]UIConstraints data...
757 */
758
759 for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
760 {
761 /*
762 * Weed out nearby duplicates, since the PPD spec requires that you
763 * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
764 */
765
766 if (i > 1 &&
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))
771 continue;
772
773 /*
774 * Allocate memory...
775 */
776
777 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
778 {
779 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
780 "UIConstraints!");
781 return;
782 }
783
784 if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
785 {
786 free(consts);
787 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
788 "UIConstraints!");
789 return;
790 }
791
792 /*
793 * Fill in the information...
794 */
795
796 consts->num_constraints = 2;
797 consts->constraints = constptr;
798
799 if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) &&
800 !_cups_strcasecmp(oldconst->choice1, "True"))
801 {
802 constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6);
803 constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom");
804 constptr[0].installable = 0;
805 }
806 else
807 {
808 constptr[0].option = ppdFindOption(ppd, oldconst->option1);
809 constptr[0].choice = ppdFindChoice(constptr[0].option,
810 oldconst->choice1);
811 constptr[0].installable = ppd_is_installable(installable,
812 oldconst->option1);
813 }
814
815 if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
816 {
817 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
818 oldconst->option1, oldconst->choice1));
819 free(consts->constraints);
820 free(consts);
821 continue;
822 }
823
824 if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) &&
825 !_cups_strcasecmp(oldconst->choice2, "True"))
826 {
827 constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6);
828 constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom");
829 constptr[1].installable = 0;
830 }
831 else
832 {
833 constptr[1].option = ppdFindOption(ppd, oldconst->option2);
834 constptr[1].choice = ppdFindChoice(constptr[1].option,
835 oldconst->choice2);
836 constptr[1].installable = ppd_is_installable(installable,
837 oldconst->option2);
838 }
839
840 if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
841 {
842 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
843 oldconst->option2, oldconst->choice2));
844 free(consts->constraints);
845 free(consts);
846 continue;
847 }
848
849 consts->installable = constptr[0].installable || constptr[1].installable;
850
851 /*
852 * Add it to the constraints array...
853 */
854
855 cupsArrayAdd(ppd->cups_uiconstraints, consts);
856 }
857
858 /*
859 * Then load new-style constraints...
860 */
861
862 for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL);
863 constattr;
864 constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
865 {
866 if (!constattr->value)
867 {
868 DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
869 continue;
870 }
871
872 for (i = 0, vptr = strchr(constattr->value, '*');
873 vptr;
874 i ++, vptr = strchr(vptr + 1, '*'));
875
876 if (i == 0)
877 {
878 DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!");
879 continue;
880 }
881
882 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
883 {
884 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
885 "cupsUIConstraints!");
886 return;
887 }
888
889 if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
890 {
891 free(consts);
892 DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for "
893 "cupsUIConstraints!");
894 return;
895 }
896
897 consts->num_constraints = i;
898 consts->constraints = constptr;
899
900 strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
901
902 for (i = 0, vptr = strchr(constattr->value, '*');
903 vptr;
904 i ++, vptr = strchr(vptr, '*'), constptr ++)
905 {
906 /*
907 * Extract "*Option Choice" or just "*Option"...
908 */
909
910 for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++)
911 if (ptr < (option + sizeof(option) - 1))
912 *ptr++ = *vptr;
913
914 *ptr = '\0';
915
916 while (_cups_isspace(*vptr))
917 vptr ++;
918
919 if (*vptr == '*')
920 choice[0] = '\0';
921 else
922 {
923 for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++)
924 if (ptr < (choice + sizeof(choice) - 1))
925 *ptr++ = *vptr;
926
927 *ptr = '\0';
928 }
929
930 if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True"))
931 {
932 _cups_strcpy(option, option + 6);
933 strlcpy(choice, "Custom", sizeof(choice));
934 }
935
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;
940
941 if (!constptr->option || (!constptr->choice && choice[0]))
942 {
943 DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!",
944 option, choice));
945 break;
946 }
947 }
948
949 if (!vptr)
950 cupsArrayAdd(ppd->cups_uiconstraints, consts);
951 else
952 {
953 free(consts->constraints);
954 free(consts);
955 }
956 }
957 }
958
959
960 /*
961 * 'ppd_test_constraints()' - See if any constraints are active.
962 */
963
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 */
972 {
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 */
982
983
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));
987
988 if (!ppd->cups_uiconstraints)
989 ppd_load_constraints(ppd);
990
991 DEBUG_printf(("9ppd_test_constraints: %d constraints!",
992 cupsArrayCount(ppd->cups_uiconstraints)));
993
994 cupsArraySave(ppd->marked);
995
996 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
997 consts;
998 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
999 {
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 : ""));
1010
1011 if (consts->installable && which < _PPD_INSTALLABLE_CONSTRAINTS)
1012 continue; /* Skip installable option constraint */
1013
1014 if (!consts->installable && which == _PPD_INSTALLABLE_CONSTRAINTS)
1015 continue; /* Skip non-installable option constraint */
1016
1017 if (which == _PPD_OPTION_CONSTRAINTS && option)
1018 {
1019 /*
1020 * Skip constraints that do not involve the current option...
1021 */
1022
1023 for (i = consts->num_constraints, constptr = consts->constraints;
1024 i > 0;
1025 i --, constptr ++)
1026 {
1027 if (!_cups_strcasecmp(constptr->option->keyword, option))
1028 break;
1029
1030 if (!_cups_strncasecmp(option, "AP_FIRSTPAGE_", 13) &&
1031 !_cups_strcasecmp(constptr->option->keyword, option + 13))
1032 break;
1033 }
1034
1035 if (!i)
1036 continue;
1037 }
1038
1039 DEBUG_puts("9ppd_test_constraints: Testing...");
1040
1041 for (i = consts->num_constraints, constptr = consts->constraints;
1042 i > 0;
1043 i --, constptr ++)
1044 {
1045 DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr->option->keyword,
1046 constptr->choice ? constptr->choice->choice : ""));
1047
1048 if (constptr->choice &&
1049 (!_cups_strcasecmp(constptr->option->keyword, "PageSize") ||
1050 !_cups_strcasecmp(constptr->option->keyword, "PageRegion")))
1051 {
1052 /*
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...
1056 */
1057
1058 if (option && choice &&
1059 (!_cups_strcasecmp(option, "PageSize") ||
1060 !_cups_strcasecmp(option, "PageRegion")))
1061 {
1062 value = choice;
1063 }
1064 else if ((value = cupsGetOption("PageSize", num_options,
1065 options)) == NULL)
1066 if ((value = cupsGetOption("PageRegion", num_options,
1067 options)) == NULL)
1068 if ((value = cupsGetOption("media", num_options, options)) == NULL)
1069 {
1070 ppd_size_t *size = ppdPageSize(ppd, NULL);
1071
1072 if (size)
1073 value = size->name;
1074 }
1075
1076 if (value && !_cups_strncasecmp(value, "Custom.", 7))
1077 value = "Custom";
1078
1079 if (option && choice &&
1080 (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") ||
1081 !_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion")))
1082 {
1083 firstvalue = choice;
1084 }
1085 else if ((firstvalue = cupsGetOption("AP_FIRSTPAGE_PageSize",
1086 num_options, options)) == NULL)
1087 firstvalue = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options,
1088 options);
1089
1090 if (firstvalue && !_cups_strncasecmp(firstvalue, "Custom.", 7))
1091 firstvalue = "Custom";
1092
1093 if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
1094 (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
1095 {
1096 DEBUG_puts("9ppd_test_constraints: NO");
1097 break;
1098 }
1099 }
1100 else if (constptr->choice)
1101 {
1102 /*
1103 * Compare against the constrained choice...
1104 */
1105
1106 if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword))
1107 {
1108 if (!_cups_strncasecmp(choice, "Custom.", 7))
1109 value = "Custom";
1110 else
1111 value = choice;
1112 }
1113 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
1114 options)) != NULL)
1115 {
1116 if (!_cups_strncasecmp(value, "Custom.", 7))
1117 value = "Custom";
1118 }
1119 else if (constptr->choice->marked)
1120 value = constptr->choice->choice;
1121 else
1122 value = NULL;
1123
1124 /*
1125 * Now check AP_FIRSTPAGE_option...
1126 */
1127
1128 snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s",
1129 constptr->option->keyword);
1130
1131 if (option && choice && !_cups_strcasecmp(option, firstpage))
1132 {
1133 if (!_cups_strncasecmp(choice, "Custom.", 7))
1134 firstvalue = "Custom";
1135 else
1136 firstvalue = choice;
1137 }
1138 else if ((firstvalue = cupsGetOption(firstpage, num_options,
1139 options)) != NULL)
1140 {
1141 if (!_cups_strncasecmp(firstvalue, "Custom.", 7))
1142 firstvalue = "Custom";
1143 }
1144 else
1145 firstvalue = NULL;
1146
1147 DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value,
1148 firstvalue));
1149
1150 if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) &&
1151 (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice)))
1152 {
1153 DEBUG_puts("9ppd_test_constraints: NO");
1154 break;
1155 }
1156 }
1157 else if (option && choice &&
1158 !_cups_strcasecmp(option, constptr->option->keyword))
1159 {
1160 if (!_cups_strcasecmp(choice, "None") || !_cups_strcasecmp(choice, "Off") ||
1161 !_cups_strcasecmp(choice, "False"))
1162 {
1163 DEBUG_puts("9ppd_test_constraints: NO");
1164 break;
1165 }
1166 }
1167 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
1168 options)) != NULL)
1169 {
1170 if (!_cups_strcasecmp(value, "None") || !_cups_strcasecmp(value, "Off") ||
1171 !_cups_strcasecmp(value, "False"))
1172 {
1173 DEBUG_puts("9ppd_test_constraints: NO");
1174 break;
1175 }
1176 }
1177 else
1178 {
1179 key.option = constptr->option;
1180
1181 if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key))
1182 == NULL ||
1183 (!_cups_strcasecmp(marked->choice, "None") ||
1184 !_cups_strcasecmp(marked->choice, "Off") ||
1185 !_cups_strcasecmp(marked->choice, "False")))
1186 {
1187 DEBUG_puts("9ppd_test_constraints: NO");
1188 break;
1189 }
1190 }
1191 }
1192
1193 if (i <= 0)
1194 {
1195 if (!active)
1196 active = cupsArrayNew(NULL, NULL);
1197
1198 cupsArrayAdd(active, consts);
1199 DEBUG_puts("9ppd_test_constraints: Added...");
1200 }
1201 }
1202
1203 cupsArrayRestore(ppd->marked);
1204
1205 DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!",
1206 cupsArrayCount(active)));
1207
1208 return (active);
1209 }
1210
1211
1212 /*
1213 * End of "$Id: conflicts.c 3933 2012-10-01 03:01:10Z msweet $".
1214 */