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