]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/conflicts.c
Merge changes from CUPS 1.4svn-r8252.
[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 */
310
311
312 for (i = consts->num_constraints, constptr = consts->constraints;
c168a833 313 i > 0 && !changed;
e78998df
MS
314 i --, constptr ++)
315 {
c168a833
MS
316 /*
317 * Can't resolve by changing an installable option...
318 */
319
320 if (constptr->installable)
e78998df
MS
321 continue;
322
c168a833
MS
323 /*
324 * Is this the option we are changing?
325 */
326
e78998df 327 if (option && !strcasecmp(constptr->option->keyword, option))
e78998df 328 continue;
e78998df 329
c168a833
MS
330 /*
331 * Get the current option choice...
332 */
333
e78998df
MS
334 if ((value = cupsGetOption(constptr->option->keyword, num_newopts,
335 newopts)) == NULL)
336 {
337 marked = ppdFindMarkedChoice(ppd, constptr->option->keyword);
338 value = marked ? marked->choice : "";
339 }
340
06d4e77b
MS
341 /*
342 * Try the default choice...
e78998df
MS
343 */
344
06d4e77b 345 test = NULL;
e78998df 346
06d4e77b
MS
347 if (strcasecmp(value, constptr->option->defchoice) &&
348 (test = ppd_test_constraints(ppd, constptr->option->keyword,
349 constptr->option->defchoice,
350 num_newopts, newopts,
351 _PPD_ALL_CONSTRAINTS)) == NULL)
e78998df 352 {
06d4e77b
MS
353 /*
354 * That worked...
355 */
356
357 num_newopts = cupsAddOption(constptr->option->keyword,
358 constptr->option->defchoice,
e78998df
MS
359 num_newopts, &newopts);
360 changed = 1;
361 }
06d4e77b
MS
362 else
363 {
364 /*
365 * Try each choice instead...
366 */
367
06d4e77b
MS
368 for (j = constptr->option->num_choices,
369 cptr = constptr->option->choices;
370 j > 0;
371 j --, cptr ++)
372 {
c168a833 373 cupsArrayDelete(test);
06d4e77b
MS
374 test = NULL;
375
376 if (strcasecmp(value, cptr->choice) &&
377 strcasecmp(constptr->option->defchoice, cptr->choice) &&
378 (test = ppd_test_constraints(ppd, constptr->option->keyword,
379 cptr->choice, num_newopts,
380 newopts,
381 _PPD_ALL_CONSTRAINTS)) == NULL)
382 {
383 /*
384 * This choice works...
385 */
386
387 num_newopts = cupsAddOption(constptr->option->keyword,
388 cptr->choice, num_newopts,
389 &newopts);
390 changed = 1;
391 break;
392 }
06d4e77b 393 }
c168a833
MS
394
395 cupsArrayDelete(test);
06d4e77b
MS
396 }
397 }
e78998df
MS
398 }
399
400 if (!changed)
401 {
402 DEBUG_puts("ppdResolveConflicts: Unable to automatically resolve "
403 "constraint!");
404 goto error;
405 }
406 }
407
408 cupsArrayClear(pass);
409 cupsArrayDelete(active);
410 }
411
412 /*
005dd1eb 413 * Free the caller's option array...
e78998df
MS
414 */
415
005dd1eb
MS
416 cupsFreeOptions(*num_options, *options);
417
418 /*
419 * If Collate is the option we are testing, add it here. Otherwise, remove
420 * any Collate option from the resolve list since the filters automatically
421 * handle manual collation...
422 */
423
424 if (option && !strcasecmp(option, "Collate"))
425 num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
e78998df 426 else
005dd1eb
MS
427 num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
428
429 /*
430 * Return the new list of options to the caller...
431 */
432
433 *num_options = num_newopts;
434 *options = newopts;
e78998df
MS
435
436 cupsArrayDelete(pass);
437 cupsArrayDelete(resolvers);
438
439 cupsArrayRestore(ppd->sorted_attrs);
440
441 return (1);
442
443 /*
444 * If we get here, we failed to resolve...
445 */
446
447 error:
448
449 cupsFreeOptions(num_newopts, newopts);
450
451 cupsArrayDelete(pass);
452 cupsArrayDelete(resolvers);
453
454 cupsArrayRestore(ppd->sorted_attrs);
455
456 return (0);
457}
458
459
06d4e77b
MS
460/*
461 * 'ppdConflicts()' - Check to see if there are any conflicts among the
462 * marked option choices.
463 *
464 * The returned value is the same as returned by @link ppdMarkOption@.
465 */
466
467int /* O - Number of conflicts found */
468ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
469{
470 int i, /* Looping variable */
471 conflicts; /* Number of conflicts */
472 cups_array_t *active; /* Active conflicts */
473 _ppd_cups_uiconsts_t *c; /* Current constraints */
474 _ppd_cups_uiconst_t *cptr; /* Current constraint */
475 ppd_option_t *o; /* Current option */
476
477
478 if (!ppd)
479 return (0);
480
481 /*
482 * Clear all conflicts...
483 */
484
485 for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd))
486 o->conflicted = 0;
487
488 /*
489 * Test for conflicts...
490 */
491
492 active = ppd_test_constraints(ppd, NULL, NULL, 0, NULL,
493 _PPD_ALL_CONSTRAINTS);
494 conflicts = cupsArrayCount(active);
495
496 /*
497 * Loop through all of the UI constraints and flag any options
498 * that conflict...
499 */
500
501 for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active);
502 c;
503 c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active))
504 {
505 for (i = c->num_constraints, cptr = c->constraints;
506 i > 0;
507 i --, cptr ++)
508 cptr->option->conflicted = 1;
509 }
510
511 cupsArrayDelete(active);
512
513 /*
514 * Return the number of conflicts found...
515 */
516
517 return (conflicts);
518}
519
520
521/*
522 * 'ppdInstallableConflict()' - Test whether an option choice conflicts with
523 * an installable option.
524 *
525 * This function tests whether a particular option choice is available based
526 * on constraints against options in the "InstallableOptions" group.
527 *
528 * @since CUPS 1.4@
529 */
530
531int /* O - 1 if conflicting, 0 if not conflicting */
532ppdInstallableConflict(
533 ppd_file_t *ppd, /* I - PPD file */
534 const char *option, /* I - Option */
535 const char *choice) /* I - Choice */
536{
537 cups_array_t *active; /* Active conflicts */
538
539
540 /*
541 * Range check input...
542 */
543
544 if (!ppd || !option || !choice)
545 return (0);
546
547 /*
548 * Test constraints using the new option...
549 */
550
551 active = ppd_test_constraints(ppd, option, choice, 0, NULL,
552 _PPD_INSTALLABLE_CONSTRAINTS);
553
554 cupsArrayDelete(active);
555
556 return (active != NULL);
557}
558
559
e78998df
MS
560/*
561 * 'ppd_is_installable()' - Determine whether an option is in the
562 * InstallableOptions group.
563 */
564
565static int /* O - 1 if installable, 0 if normal */
566ppd_is_installable(
567 ppd_group_t *installable, /* I - InstallableOptions group */
568 const char *name) /* I - Option name */
569{
570 if (installable)
571 {
572 int i; /* Looping var */
573 ppd_option_t *option; /* Current option */
574
575
576 for (i = installable->num_options, option = installable->options;
577 i > 0;
578 i --, option ++)
579 if (!strcasecmp(option->keyword, name))
580 return (1);
581 }
582
583 return (0);
584}
585
586
587/*
588 * 'ppd_load_constraints()' - Load constraints from a PPD file.
589 */
590
591static void
592ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */
593{
594 int i; /* Looping var */
595 ppd_const_t *oldconst; /* Current UIConstraints data */
596 ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */
597 _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */
598 _ppd_cups_uiconst_t *constptr; /* Current constraint */
599 ppd_group_t *installable; /* Installable options group */
600 const char *vptr; /* Pointer into constraint value */
601 char option[PPD_MAX_NAME], /* Option name/MainKeyword */
602 choice[PPD_MAX_NAME], /* Choice/OptionKeyword */
603 *ptr; /* Pointer into option or choice */
604
605
606 /*
607 * Create an array to hold the constraint data...
608 */
609
610 ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL);
611
612 /*
613 * Find the installable options group if it exists...
614 */
615
616 for (i = ppd->num_groups, installable = ppd->groups;
617 i > 0;
618 i --, installable ++)
619 if (!strcasecmp(installable->name, "InstallableOptions"))
620 break;
621
622 if (i <= 0)
623 installable = NULL;
624
625 /*
28b9d139 626 * Load old-style [Non]UIConstraints data...
e78998df
MS
627 */
628
28b9d139 629 for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++)
e78998df
MS
630 {
631 /*
28b9d139
MS
632 * Weed out nearby duplicates, since the PPD spec requires that you
633 * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"...
e78998df
MS
634 */
635
28b9d139
MS
636 if (i > 1 &&
637 !strcasecmp(oldconst[0].option1, oldconst[1].option2) &&
638 !strcasecmp(oldconst[0].choice1, oldconst[1].choice2) &&
639 !strcasecmp(oldconst[0].option2, oldconst[1].option1) &&
640 !strcasecmp(oldconst[0].choice2, oldconst[1].choice1))
641 continue;
e78998df 642
28b9d139
MS
643 /*
644 * Allocate memory...
645 */
e78998df 646
28b9d139
MS
647 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
648 {
649 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
650 "UIConstraints!");
651 return;
652 }
e78998df 653
28b9d139
MS
654 if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL)
655 {
656 free(consts);
657 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
658 "UIConstraints!");
659 return;
660 }
e78998df 661
28b9d139
MS
662 /*
663 * Fill in the information...
664 */
e78998df 665
28b9d139
MS
666 consts->num_constraints = 2;
667 consts->constraints = constptr;
e78998df 668
28b9d139
MS
669 if (!strncasecmp(oldconst->option1, "Custom", 6) &&
670 !strcasecmp(oldconst->choice1, "True"))
671 {
672 constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6);
673 constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom");
674 constptr[0].installable = 0;
675 }
676 else
677 {
678 constptr[0].option = ppdFindOption(ppd, oldconst->option1);
679 constptr[0].choice = ppdFindChoice(constptr[0].option,
680 oldconst->choice1);
681 constptr[0].installable = ppd_is_installable(installable,
682 oldconst->option1);
683 }
e78998df 684
28b9d139
MS
685 if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
686 {
687 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
688 oldconst->option1, oldconst->choice1));
689 free(consts->constraints);
690 free(consts);
691 continue;
692 }
e78998df 693
28b9d139
MS
694 if (!strncasecmp(oldconst->option2, "Custom", 6) &&
695 !strcasecmp(oldconst->choice2, "True"))
696 {
697 constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6);
698 constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom");
699 constptr[1].installable = 0;
700 }
701 else
702 {
703 constptr[1].option = ppdFindOption(ppd, oldconst->option2);
704 constptr[1].choice = ppdFindChoice(constptr[1].option,
705 oldconst->choice2);
706 constptr[1].installable = ppd_is_installable(installable,
707 oldconst->option2);
708 }
e78998df 709
28b9d139
MS
710 if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
711 {
712 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
713 oldconst->option2, oldconst->choice2));
714 free(consts->constraints);
715 free(consts);
716 continue;
717 }
e78998df 718
28b9d139 719 consts->installable = constptr[0].installable || constptr[1].installable;
e78998df 720
28b9d139
MS
721 /*
722 * Add it to the constraints array...
723 */
e78998df 724
28b9d139
MS
725 cupsArrayAdd(ppd->cups_uiconstraints, consts);
726 }
e78998df 727
28b9d139
MS
728 /*
729 * Then load new-style constraints...
730 */
e78998df 731
28b9d139
MS
732 for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL);
733 constattr;
734 constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL))
735 {
736 if (!constattr->value)
737 {
738 DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
739 continue;
740 }
e78998df 741
28b9d139
MS
742 for (i = 0, vptr = strchr(constattr->value, '*');
743 vptr;
744 i ++, vptr = strchr(vptr + 1, '*'));
e78998df 745
28b9d139
MS
746 if (i == 0)
747 {
748 DEBUG_puts("ppd_load_constraints: Bad cupsUIConstraints value!");
749 continue;
e78998df 750 }
e78998df 751
28b9d139 752 if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL)
e78998df 753 {
28b9d139
MS
754 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
755 "cupsUIConstraints!");
756 return;
757 }
e78998df 758
28b9d139
MS
759 if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL)
760 {
761 free(consts);
762 DEBUG_puts("ppd_load_constraints: Unable to allocate memory for "
763 "cupsUIConstraints!");
764 return;
765 }
e78998df 766
28b9d139
MS
767 consts->num_constraints = i;
768 consts->constraints = constptr;
e78998df 769
28b9d139 770 strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver));
e78998df 771
28b9d139
MS
772 for (i = 0, vptr = strchr(constattr->value, '*');
773 vptr;
774 i ++, vptr = strchr(vptr, '*'), constptr ++)
775 {
e78998df 776 /*
28b9d139 777 * Extract "*Option Choice" or just "*Option"...
e78998df
MS
778 */
779
28b9d139
MS
780 for (vptr ++, ptr = option; *vptr && !isspace(*vptr & 255); vptr ++)
781 if (ptr < (option + sizeof(option) - 1))
782 *ptr++ = *vptr;
e78998df 783
28b9d139 784 *ptr = '\0';
e78998df 785
28b9d139
MS
786 while (isspace(*vptr & 255))
787 vptr ++;
e78998df 788
28b9d139
MS
789 if (*vptr == '*')
790 choice[0] = '\0';
e78998df
MS
791 else
792 {
28b9d139
MS
793 for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
794 if (ptr < (choice + sizeof(choice) - 1))
795 *ptr++ = *vptr;
796
797 *ptr = '\0';
e78998df
MS
798 }
799
28b9d139 800 if (!strncasecmp(option, "Custom", 6) && !strcasecmp(choice, "True"))
e78998df 801 {
28b9d139
MS
802 _cups_strcpy(option, option + 6);
803 strcpy(choice, "Custom");
e78998df
MS
804 }
805
28b9d139
MS
806 constptr->option = ppdFindOption(ppd, option);
807 constptr->choice = ppdFindChoice(constptr->option, choice);
808 constptr->installable = ppd_is_installable(installable, option);
809 consts->installable |= constptr->installable;
e78998df 810
28b9d139
MS
811 if (!constptr->option || (!constptr->choice && choice[0]))
812 {
813 DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
814 option, choice));
815 break;
816 }
817 }
e78998df 818
28b9d139 819 if (!vptr)
e78998df 820 cupsArrayAdd(ppd->cups_uiconstraints, consts);
28b9d139
MS
821 else
822 {
823 free(consts->constraints);
824 free(consts);
e78998df
MS
825 }
826 }
827}
828
829
e78998df
MS
830/*
831 * 'ppd_test_constraints()' - See if any constraints are active.
832 */
833
834static cups_array_t * /* O - Array of active constraints */
835ppd_test_constraints(
836 ppd_file_t *ppd, /* I - PPD file */
06d4e77b
MS
837 const char *option, /* I - Current option */
838 const char *choice, /* I - Current choice */
e78998df
MS
839 int num_options, /* I - Number of additional options */
840 cups_option_t *options, /* I - Additional options */
841 int which) /* I - Which constraints to test */
842{
843 int i; /* Looping var */
844 _ppd_cups_uiconsts_t *consts; /* Current constraints */
845 _ppd_cups_uiconst_t *constptr; /* Current constraint */
846 ppd_choice_t key, /* Search key */
847 *marked; /* Marked choice */
848 cups_array_t *active = NULL; /* Active constraints */
849 const char *value; /* Current value */
06d4e77b
MS
850 int option_conflict;/* Conflict with current option? */
851
e78998df 852
06d4e77b
MS
853 DEBUG_printf(("ppd_test_constraints(ppd=%p, num_options=%d, options=%p, "
854 "which=%d)\n", ppd, num_options, options, which));
e78998df
MS
855
856 if (!ppd->cups_uiconstraints)
857 ppd_load_constraints(ppd);
858
06d4e77b
MS
859 DEBUG_printf(("ppd_test_constraints: %d constraints!\n",
860 cupsArrayCount(ppd->cups_uiconstraints)));
861
e78998df
MS
862 cupsArraySave(ppd->marked);
863
864 for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
865 consts;
866 consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
867 {
06d4e77b
MS
868 DEBUG_printf(("ppd_test_constraints: installable=%d, resolver=\"%s\", "
869 "num_constraints=%d option1=\"%s\", choice1=\"%s\", "
870 "option2=\"%s\", choice2=\"%s\", ...\n",
871 consts->installable, consts->resolver, consts->num_constraints,
872 consts->constraints[0].option->keyword,
873 consts->constraints[0].choice ?
874 consts->constraints[0].choice->choice : "",
875 consts->constraints[1].option->keyword,
876 consts->constraints[1].choice ?
877 consts->constraints[1].choice->choice : ""));
878
e78998df
MS
879 if (which != _PPD_ALL_CONSTRAINTS && which != consts->installable)
880 continue;
881
06d4e77b
MS
882 DEBUG_puts("ppd_test_constraints: Testing...");
883
884 for (i = consts->num_constraints, constptr = consts->constraints,
885 option_conflict = 0;
e78998df
MS
886 i > 0;
887 i --, constptr ++)
888 {
06d4e77b
MS
889 DEBUG_printf(("ppd_test_constraints: %s=%s?\n", constptr->option->keyword,
890 constptr->choice ? constptr->choice->choice : ""));
891
e78998df
MS
892 if (constptr->choice &&
893 (!strcasecmp(constptr->option->keyword, "PageSize") ||
894 !strcasecmp(constptr->option->keyword, "PageRegion")))
895 {
896 /*
897 * PageSize and PageRegion are used depending on the selected input slot
898 * and manual feed mode. Validate against the selected page size instead
899 * of an individual option...
900 */
901
06d4e77b
MS
902 if (option && choice &&
903 (!strcasecmp(option, "PageSize") ||
904 !strcasecmp(option, "PageRegion")))
905 {
906 value = choice;
907
908 if (!strcasecmp(value, constptr->choice->choice))
909 option_conflict = 1;
910 }
911 else if ((value = cupsGetOption("PageSize", num_options,
912 options)) == NULL)
e78998df
MS
913 if ((value = cupsGetOption("PageRegion", num_options,
914 options)) == NULL)
915 if ((value = cupsGetOption("media", num_options, options)) == NULL)
916 {
917 ppd_size_t *size = ppdPageSize(ppd, NULL);
918
919 if (size)
920 value = size->name;
921 }
922
923 if (!value || strcasecmp(value, constptr->choice->choice))
06d4e77b
MS
924 {
925 DEBUG_puts("ppd_test_constraints: NO");
e78998df 926 break;
06d4e77b 927 }
e78998df
MS
928 }
929 else if (constptr->choice)
930 {
06d4e77b
MS
931 if (option && choice && !strcasecmp(option, constptr->option->keyword))
932 {
933 if (strcasecmp(choice, constptr->choice->choice))
934 break;
935
936 option_conflict = 1;
937 }
938 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
939 options)) != NULL)
e78998df
MS
940 {
941 if (strcasecmp(value, constptr->choice->choice))
06d4e77b
MS
942 {
943 DEBUG_puts("ppd_test_constraints: NO");
e78998df 944 break;
06d4e77b 945 }
e78998df
MS
946 }
947 else if (!constptr->choice->marked)
06d4e77b
MS
948 {
949 DEBUG_puts("ppd_test_constraints: NO");
950 break;
951 }
952 }
953 else if (option && choice &&
954 !strcasecmp(option, constptr->option->keyword))
955 {
956 if (!strcasecmp(choice, "None") || !strcasecmp(choice, "Off") ||
957 !strcasecmp(choice, "False"))
e78998df 958 break;
06d4e77b
MS
959
960 option_conflict = 1;
e78998df
MS
961 }
962 else if ((value = cupsGetOption(constptr->option->keyword, num_options,
963 options)) != NULL)
964 {
965 if (!strcasecmp(value, "None") || !strcasecmp(value, "Off") ||
966 !strcasecmp(value, "False"))
06d4e77b
MS
967 {
968 DEBUG_puts("ppd_test_constraints: NO");
969 break;
970 }
e78998df
MS
971 }
972 else
973 {
974 key.option = constptr->option;
975
976 if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key))
977 != NULL &&
978 (!strcasecmp(marked->choice, "None") ||
979 !strcasecmp(marked->choice, "Off") ||
980 !strcasecmp(marked->choice, "False")))
06d4e77b
MS
981 {
982 DEBUG_puts("ppd_test_constraints: NO");
e78998df 983 break;
06d4e77b 984 }
e78998df
MS
985 }
986 }
987
06d4e77b 988 if (i <= 0 && (!option || option_conflict))
e78998df
MS
989 {
990 if (!active)
991 active = cupsArrayNew(NULL, NULL);
992
993 cupsArrayAdd(active, consts);
06d4e77b 994 DEBUG_puts("ppd_test_constraints: Added...");
e78998df
MS
995 }
996 }
997
998 cupsArrayRestore(ppd->marked);
999
06d4e77b
MS
1000 DEBUG_printf(("ppd_test_constraints: Found %d active constraints!\n",
1001 cupsArrayCount(active)));
1002
e78998df
MS
1003 return (active);
1004}
1005
1006
1007/*
1008 * End of "$Id$".
1009 */