]>
Commit | Line | Data |
---|---|---|
e78998df MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
71e16022 | 4 | * Option marking routines for CUPS. |
e78998df | 5 | * |
f3c17241 | 6 | * Copyright 2007-2012 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 | ||
71e16022 | 38 | #include "cups-private.h" |
e78998df | 39 | #include "ppd-private.h" |
e78998df MS |
40 | |
41 | ||
42 | /* | |
43 | * Local constants... | |
44 | */ | |
45 | ||
46 | enum | |
47 | { | |
48 | _PPD_NORMAL_CONSTRAINTS, | |
e07d4801 | 49 | _PPD_OPTION_CONSTRAINTS, |
e78998df MS |
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); | |
06d4e77b MS |
62 | static 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 | * | |
f3c17241 | 82 | * @since CUPS 1.4/OS X 10.6@ |
d2354e63 MS |
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 */ | |
07ed0e9a | 97 | ppd_choice_t *marked; /* Marked choice */ |
d2354e63 MS |
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 ++) | |
88f9aafc | 128 | if (_cups_strcasecmp(cptr->option->keyword, option)) |
07ed0e9a MS |
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 | } | |
d2354e63 MS |
139 | } |
140 | ||
141 | cupsArrayDelete(active); | |
142 | ||
143 | return (num_options); | |
144 | } | |
145 | ||
146 | ||
e78998df MS |
147 | /* |
148 | * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD. | |
149 | * | |
150 | * This function attempts to resolve any conflicts in a marked PPD, returning | |
06d4e77b MS |
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 | |
e78998df MS |
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 | |
06d4e77b MS |
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. | |
e78998df | 162 | * |
06d4e77b MS |
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 | |
e78998df | 172 | * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this |
06d4e77b | 173 | * case, the PPD file provides constraint resolution actions. |
e78998df | 174 | * |
06d4e77b | 175 | * The backup constraint information is defined by the |
e78998df | 176 | * @code UIConstraints@ and @code NonUIConstraints@ attributes. These |
06d4e77b MS |
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. | |
e78998df | 180 | * |
f3c17241 | 181 | * @since CUPS 1.4/OS X 10.6@ |
e78998df MS |
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 */ | |
b0f6947b | 193 | tries, /* Number of tries */ |
1340db2d MS |
194 | num_newopts; /* Number of new options */ |
195 | cups_option_t *newopts; /* New options */ | |
e78998df MS |
196 | cups_array_t *active, /* Active constraints */ |
197 | *pass, /* Resolvers for this pass */ | |
1340db2d MS |
198 | *resolvers, /* Resolvers we have used */ |
199 | *test; /* Test array for conflicts */ | |
e78998df MS |
200 | _ppd_cups_uiconsts_t *consts; /* Current constraints */ |
201 | _ppd_cups_uiconst_t *constptr; /* Current constraint */ | |
202 | ppd_attr_t *resolver; /* Current resolver */ | |
1340db2d MS |
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 */ | |
e60ec91f MS |
208 | *resptr, /* Pointer into option/choice */ |
209 | firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ | |
e78998df MS |
210 | const char *value; /* Selected option value */ |
211 | int changed; /* Did we change anything? */ | |
212 | ppd_choice_t *marked; /* Marked choice */ | |
e78998df MS |
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); | |
88f9aafc | 232 | if (option && _cups_strcasecmp(option, "Collate")) |
e78998df MS |
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; | |
88f9aafc | 242 | pass = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); |
b0f6947b | 243 | tries = 0; |
e78998df | 244 | |
b0f6947b MS |
245 | while (tries < 100 && |
246 | (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts, | |
e78998df MS |
247 | _PPD_ALL_CONSTRAINTS)) != NULL) |
248 | { | |
b0f6947b MS |
249 | tries ++; |
250 | ||
e78998df | 251 | if (!resolvers) |
88f9aafc | 252 | resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); |
e78998df MS |
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 | ||
f99f3698 | 273 | DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!", |
e78998df MS |
274 | consts->resolver)); |
275 | goto error; | |
276 | } | |
277 | ||
278 | if ((resolver = ppdFindAttr(ppd, "cupsUIResolver", | |
279 | consts->resolver)) == NULL) | |
280 | { | |
f99f3698 | 281 | DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!", |
e78998df MS |
282 | consts->resolver)); |
283 | goto error; | |
284 | } | |
285 | ||
286 | if (!resolver->value) | |
287 | { | |
f99f3698 | 288 | DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!", |
e78998df MS |
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 | ||
1340db2d | 300 | for (resval = resolver->value; *resval && !changed;) |
06d4e77b | 301 | { |
7cf5915e | 302 | while (_cups_isspace(*resval)) |
1340db2d | 303 | resval ++; |
06d4e77b | 304 | |
1340db2d MS |
305 | if (*resval != '*') |
306 | break; | |
307 | ||
308 | for (resval ++, resptr = resoption; | |
7cf5915e | 309 | *resval && !_cups_isspace(*resval); |
1340db2d MS |
310 | resval ++) |
311 | if (resptr < (resoption + sizeof(resoption) - 1)) | |
312 | *resptr++ = *resval; | |
313 | ||
314 | *resptr = '\0'; | |
315 | ||
7cf5915e | 316 | while (_cups_isspace(*resval)) |
1340db2d MS |
317 | resval ++; |
318 | ||
319 | for (resptr = reschoice; | |
7cf5915e | 320 | *resval && !_cups_isspace(*resval); |
1340db2d MS |
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 | ||
e60ec91f MS |
334 | snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption); |
335 | ||
1340db2d | 336 | if (option && |
88f9aafc MS |
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")))) | |
1340db2d MS |
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) | |
06d4e77b | 360 | { |
1340db2d MS |
361 | /* |
362 | * That worked... | |
363 | */ | |
06d4e77b | 364 | |
1340db2d MS |
365 | changed = 1; |
366 | } | |
367 | else | |
368 | cupsArrayDelete(test); | |
06d4e77b | 369 | |
1340db2d MS |
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 | } | |
e78998df MS |
379 | } |
380 | else | |
381 | { | |
382 | /* | |
383 | * Try resolving by choosing the default values for non-installable | |
06d4e77b | 384 | * options, then by iterating through the possible choices... |
e78998df MS |
385 | */ |
386 | ||
06d4e77b MS |
387 | int j; /* Looping var */ |
388 | ppd_choice_t *cptr; /* Current choice */ | |
d1c13e16 | 389 | ppd_size_t *size; /* Current page size */ |
06d4e77b MS |
390 | |
391 | ||
392 | for (i = consts->num_constraints, constptr = consts->constraints; | |
c168a833 | 393 | i > 0 && !changed; |
e78998df MS |
394 | i --, constptr ++) |
395 | { | |
c168a833 MS |
396 | /* |
397 | * Can't resolve by changing an installable option... | |
398 | */ | |
399 | ||
400 | if (constptr->installable) | |
e78998df MS |
401 | continue; |
402 | ||
c168a833 MS |
403 | /* |
404 | * Is this the option we are changing? | |
405 | */ | |
406 | ||
d1c13e16 | 407 | if (option && |
88f9aafc MS |
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")))) | |
e78998df | 413 | continue; |
e78998df | 414 | |
c168a833 MS |
415 | /* |
416 | * Get the current option choice... | |
417 | */ | |
418 | ||
e78998df MS |
419 | if ((value = cupsGetOption(constptr->option->keyword, num_newopts, |
420 | newopts)) == NULL) | |
421 | { | |
88f9aafc MS |
422 | if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || |
423 | !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) | |
d1c13e16 MS |
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 | } | |
e78998df MS |
442 | } |
443 | ||
88f9aafc | 444 | if (!_cups_strncasecmp(value, "Custom.", 7)) |
d1c13e16 MS |
445 | value = "Custom"; |
446 | ||
06d4e77b MS |
447 | /* |
448 | * Try the default choice... | |
e78998df MS |
449 | */ |
450 | ||
06d4e77b | 451 | test = NULL; |
e78998df | 452 | |
88f9aafc | 453 | if (_cups_strcasecmp(value, constptr->option->defchoice) && |
06d4e77b MS |
454 | (test = ppd_test_constraints(ppd, constptr->option->keyword, |
455 | constptr->option->defchoice, | |
456 | num_newopts, newopts, | |
e07d4801 | 457 | _PPD_OPTION_CONSTRAINTS)) == NULL) |
e78998df | 458 | { |
06d4e77b MS |
459 | /* |
460 | * That worked... | |
461 | */ | |
462 | ||
463 | num_newopts = cupsAddOption(constptr->option->keyword, | |
464 | constptr->option->defchoice, | |
e78998df MS |
465 | num_newopts, &newopts); |
466 | changed = 1; | |
467 | } | |
06d4e77b MS |
468 | else |
469 | { | |
470 | /* | |
471 | * Try each choice instead... | |
472 | */ | |
473 | ||
06d4e77b MS |
474 | for (j = constptr->option->num_choices, |
475 | cptr = constptr->option->choices; | |
476 | j > 0; | |
477 | j --, cptr ++) | |
478 | { | |
c168a833 | 479 | cupsArrayDelete(test); |
06d4e77b MS |
480 | test = NULL; |
481 | ||
88f9aafc MS |
482 | if (_cups_strcasecmp(value, cptr->choice) && |
483 | _cups_strcasecmp(constptr->option->defchoice, cptr->choice) && | |
484 | _cups_strcasecmp("Custom", cptr->choice) && | |
06d4e77b MS |
485 | (test = ppd_test_constraints(ppd, constptr->option->keyword, |
486 | cptr->choice, num_newopts, | |
487 | newopts, | |
e07d4801 | 488 | _PPD_OPTION_CONSTRAINTS)) == NULL) |
06d4e77b MS |
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 | } | |
06d4e77b | 500 | } |
c168a833 MS |
501 | |
502 | cupsArrayDelete(test); | |
06d4e77b MS |
503 | } |
504 | } | |
e78998df | 505 | } |
0268488e | 506 | } |
e78998df | 507 | |
0268488e MS |
508 | if (!changed) |
509 | { | |
f99f3698 | 510 | DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve " |
0268488e MS |
511 | "constraint!"); |
512 | goto error; | |
e78998df MS |
513 | } |
514 | ||
515 | cupsArrayClear(pass); | |
516 | cupsArrayDelete(active); | |
b0f6947b | 517 | active = NULL; |
e78998df MS |
518 | } |
519 | ||
b0f6947b MS |
520 | if (tries >= 100) |
521 | goto error; | |
522 | ||
e78998df | 523 | /* |
005dd1eb | 524 | * Free the caller's option array... |
e78998df MS |
525 | */ |
526 | ||
005dd1eb MS |
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 | ||
88f9aafc | 535 | if (option && !_cups_strcasecmp(option, "Collate")) |
005dd1eb | 536 | num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); |
e78998df | 537 | else |
005dd1eb MS |
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; | |
e78998df MS |
546 | |
547 | cupsArrayDelete(pass); | |
548 | cupsArrayDelete(resolvers); | |
549 | ||
550 | cupsArrayRestore(ppd->sorted_attrs); | |
551 | ||
e07d4801 | 552 | DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts)); |
d1c13e16 MS |
553 | #ifdef DEBUG |
554 | for (i = 0; i < num_newopts; i ++) | |
e07d4801 | 555 | DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i, |
d1c13e16 MS |
556 | newopts[i].name, newopts[i].value)); |
557 | #endif /* DEBUG */ | |
558 | ||
e78998df MS |
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 | ||
94da7e34 | 569 | cupsArrayDelete(active); |
e78998df MS |
570 | cupsArrayDelete(pass); |
571 | cupsArrayDelete(resolvers); | |
572 | ||
573 | cupsArrayRestore(ppd->sorted_attrs); | |
574 | ||
e07d4801 | 575 | DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!"); |
d1c13e16 | 576 | |
e78998df MS |
577 | return (0); |
578 | } | |
579 | ||
580 | ||
06d4e77b MS |
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 | ||
ef55b745 MS |
606 | cupsArraySave(ppd->options); |
607 | ||
06d4e77b MS |
608 | for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd)) |
609 | o->conflicted = 0; | |
610 | ||
ef55b745 MS |
611 | cupsArrayRestore(ppd->options); |
612 | ||
06d4e77b MS |
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 | * | |
f3c17241 | 653 | * @since CUPS 1.4/OS X 10.6@ |
06d4e77b MS |
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 | ||
e07d4801 MS |
665 | DEBUG_printf(("2ppdInstallableConflict(ppd=%p, option=\"%s\", choice=\"%s\")", |
666 | ppd, option, choice)); | |
667 | ||
ef55b745 | 668 | /* |
06d4e77b MS |
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 | ||
e78998df MS |
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 ++) | |
88f9aafc | 707 | if (!_cups_strcasecmp(option->keyword, name)) |
e78998df MS |
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 | ||
e07d4801 MS |
734 | DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd)); |
735 | ||
e78998df MS |
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 ++) | |
88f9aafc | 749 | if (!_cups_strcasecmp(installable->name, "InstallableOptions")) |
e78998df MS |
750 | break; |
751 | ||
752 | if (i <= 0) | |
753 | installable = NULL; | |
754 | ||
755 | /* | |
28b9d139 | 756 | * Load old-style [Non]UIConstraints data... |
e78998df MS |
757 | */ |
758 | ||
28b9d139 | 759 | for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++) |
e78998df MS |
760 | { |
761 | /* | |
28b9d139 MS |
762 | * Weed out nearby duplicates, since the PPD spec requires that you |
763 | * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"... | |
e78998df MS |
764 | */ |
765 | ||
28b9d139 | 766 | if (i > 1 && |
88f9aafc MS |
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)) | |
28b9d139 | 771 | continue; |
e78998df | 772 | |
28b9d139 MS |
773 | /* |
774 | * Allocate memory... | |
775 | */ | |
e78998df | 776 | |
28b9d139 MS |
777 | if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) |
778 | { | |
e07d4801 | 779 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
780 | "UIConstraints!"); |
781 | return; | |
782 | } | |
e78998df | 783 | |
28b9d139 MS |
784 | if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL) |
785 | { | |
786 | free(consts); | |
e07d4801 | 787 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
788 | "UIConstraints!"); |
789 | return; | |
790 | } | |
e78998df | 791 | |
28b9d139 MS |
792 | /* |
793 | * Fill in the information... | |
794 | */ | |
e78998df | 795 | |
28b9d139 MS |
796 | consts->num_constraints = 2; |
797 | consts->constraints = constptr; | |
e78998df | 798 | |
88f9aafc MS |
799 | if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) && |
800 | !_cups_strcasecmp(oldconst->choice1, "True")) | |
28b9d139 MS |
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 | } | |
e78998df | 814 | |
28b9d139 MS |
815 | if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0])) |
816 | { | |
e07d4801 | 817 | DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", |
28b9d139 MS |
818 | oldconst->option1, oldconst->choice1)); |
819 | free(consts->constraints); | |
820 | free(consts); | |
821 | continue; | |
822 | } | |
e78998df | 823 | |
88f9aafc MS |
824 | if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) && |
825 | !_cups_strcasecmp(oldconst->choice2, "True")) | |
28b9d139 MS |
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 | } | |
e78998df | 839 | |
28b9d139 MS |
840 | if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0])) |
841 | { | |
e07d4801 | 842 | DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", |
28b9d139 MS |
843 | oldconst->option2, oldconst->choice2)); |
844 | free(consts->constraints); | |
845 | free(consts); | |
846 | continue; | |
847 | } | |
e78998df | 848 | |
28b9d139 | 849 | consts->installable = constptr[0].installable || constptr[1].installable; |
e78998df | 850 | |
28b9d139 MS |
851 | /* |
852 | * Add it to the constraints array... | |
853 | */ | |
e78998df | 854 | |
28b9d139 MS |
855 | cupsArrayAdd(ppd->cups_uiconstraints, consts); |
856 | } | |
e78998df | 857 | |
28b9d139 MS |
858 | /* |
859 | * Then load new-style constraints... | |
860 | */ | |
e78998df | 861 | |
28b9d139 MS |
862 | for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL); |
863 | constattr; | |
864 | constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL)) | |
865 | { | |
866 | if (!constattr->value) | |
867 | { | |
e07d4801 | 868 | DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); |
28b9d139 MS |
869 | continue; |
870 | } | |
e78998df | 871 | |
28b9d139 MS |
872 | for (i = 0, vptr = strchr(constattr->value, '*'); |
873 | vptr; | |
874 | i ++, vptr = strchr(vptr + 1, '*')); | |
e78998df | 875 | |
28b9d139 MS |
876 | if (i == 0) |
877 | { | |
e07d4801 | 878 | DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); |
28b9d139 | 879 | continue; |
e78998df | 880 | } |
e78998df | 881 | |
28b9d139 | 882 | if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) |
e78998df | 883 | { |
e07d4801 | 884 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
885 | "cupsUIConstraints!"); |
886 | return; | |
887 | } | |
e78998df | 888 | |
28b9d139 MS |
889 | if ((constptr = calloc(i, sizeof(_ppd_cups_uiconst_t))) == NULL) |
890 | { | |
891 | free(consts); | |
e07d4801 | 892 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
893 | "cupsUIConstraints!"); |
894 | return; | |
895 | } | |
e78998df | 896 | |
28b9d139 MS |
897 | consts->num_constraints = i; |
898 | consts->constraints = constptr; | |
e78998df | 899 | |
28b9d139 | 900 | strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver)); |
e78998df | 901 | |
28b9d139 MS |
902 | for (i = 0, vptr = strchr(constattr->value, '*'); |
903 | vptr; | |
904 | i ++, vptr = strchr(vptr, '*'), constptr ++) | |
905 | { | |
e78998df | 906 | /* |
28b9d139 | 907 | * Extract "*Option Choice" or just "*Option"... |
e78998df MS |
908 | */ |
909 | ||
7cf5915e | 910 | for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++) |
28b9d139 MS |
911 | if (ptr < (option + sizeof(option) - 1)) |
912 | *ptr++ = *vptr; | |
e78998df | 913 | |
28b9d139 | 914 | *ptr = '\0'; |
e78998df | 915 | |
7cf5915e | 916 | while (_cups_isspace(*vptr)) |
28b9d139 | 917 | vptr ++; |
e78998df | 918 | |
28b9d139 MS |
919 | if (*vptr == '*') |
920 | choice[0] = '\0'; | |
e78998df MS |
921 | else |
922 | { | |
7cf5915e | 923 | for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++) |
28b9d139 MS |
924 | if (ptr < (choice + sizeof(choice) - 1)) |
925 | *ptr++ = *vptr; | |
926 | ||
927 | *ptr = '\0'; | |
e78998df MS |
928 | } |
929 | ||
88f9aafc | 930 | if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True")) |
e78998df | 931 | { |
28b9d139 | 932 | _cups_strcpy(option, option + 6); |
5a9febac | 933 | strlcpy(choice, "Custom", sizeof(choice)); |
e78998df MS |
934 | } |
935 | ||
28b9d139 MS |
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; | |
e78998df | 940 | |
28b9d139 MS |
941 | if (!constptr->option || (!constptr->choice && choice[0])) |
942 | { | |
e07d4801 | 943 | DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", |
28b9d139 MS |
944 | option, choice)); |
945 | break; | |
946 | } | |
947 | } | |
e78998df | 948 | |
28b9d139 | 949 | if (!vptr) |
e78998df | 950 | cupsArrayAdd(ppd->cups_uiconstraints, consts); |
28b9d139 MS |
951 | else |
952 | { | |
953 | free(consts->constraints); | |
954 | free(consts); | |
e78998df MS |
955 | } |
956 | } | |
957 | } | |
958 | ||
959 | ||
e78998df MS |
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 */ | |
06d4e77b MS |
967 | const char *option, /* I - Current option */ |
968 | const char *choice, /* I - Current choice */ | |
e78998df MS |
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 */ | |
e60ec91f MS |
979 | const char *value, /* Current value */ |
980 | *firstvalue; /* AP_FIRSTPAGE_Keyword value */ | |
981 | char firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ | |
06d4e77b | 982 | |
e78998df | 983 | |
e07d4801 MS |
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)); | |
e78998df MS |
987 | |
988 | if (!ppd->cups_uiconstraints) | |
989 | ppd_load_constraints(ppd); | |
990 | ||
e07d4801 | 991 | DEBUG_printf(("9ppd_test_constraints: %d constraints!", |
06d4e77b MS |
992 | cupsArrayCount(ppd->cups_uiconstraints))); |
993 | ||
e78998df MS |
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 | { | |
e07d4801 | 1000 | DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", " |
06d4e77b | 1001 | "num_constraints=%d option1=\"%s\", choice1=\"%s\", " |
e07d4801 | 1002 | "option2=\"%s\", choice2=\"%s\", ...", |
06d4e77b MS |
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 | ||
e07d4801 MS |
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 ++) | |
e60ec91f | 1026 | { |
88f9aafc | 1027 | if (!_cups_strcasecmp(constptr->option->keyword, option)) |
e07d4801 MS |
1028 | break; |
1029 | ||
88f9aafc MS |
1030 | if (!_cups_strncasecmp(option, "AP_FIRSTPAGE_", 13) && |
1031 | !_cups_strcasecmp(constptr->option->keyword, option + 13)) | |
e60ec91f MS |
1032 | break; |
1033 | } | |
1034 | ||
e07d4801 MS |
1035 | if (!i) |
1036 | continue; | |
1037 | } | |
e78998df | 1038 | |
e07d4801 | 1039 | DEBUG_puts("9ppd_test_constraints: Testing..."); |
06d4e77b | 1040 | |
d1c13e16 | 1041 | for (i = consts->num_constraints, constptr = consts->constraints; |
e78998df MS |
1042 | i > 0; |
1043 | i --, constptr ++) | |
1044 | { | |
e07d4801 | 1045 | DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr->option->keyword, |
06d4e77b MS |
1046 | constptr->choice ? constptr->choice->choice : "")); |
1047 | ||
e78998df | 1048 | if (constptr->choice && |
88f9aafc MS |
1049 | (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || |
1050 | !_cups_strcasecmp(constptr->option->keyword, "PageRegion"))) | |
e78998df MS |
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 | ||
06d4e77b | 1058 | if (option && choice && |
88f9aafc MS |
1059 | (!_cups_strcasecmp(option, "PageSize") || |
1060 | !_cups_strcasecmp(option, "PageRegion"))) | |
06d4e77b MS |
1061 | { |
1062 | value = choice; | |
06d4e77b MS |
1063 | } |
1064 | else if ((value = cupsGetOption("PageSize", num_options, | |
1065 | options)) == NULL) | |
e78998df MS |
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 | ||
88f9aafc | 1076 | if (value && !_cups_strncasecmp(value, "Custom.", 7)) |
d1c13e16 MS |
1077 | value = "Custom"; |
1078 | ||
e60ec91f | 1079 | if (option && choice && |
88f9aafc MS |
1080 | (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") || |
1081 | !_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion"))) | |
e60ec91f MS |
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 | ||
88f9aafc | 1090 | if (firstvalue && !_cups_strncasecmp(firstvalue, "Custom.", 7)) |
e60ec91f MS |
1091 | firstvalue = "Custom"; |
1092 | ||
88f9aafc MS |
1093 | if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) && |
1094 | (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice))) | |
06d4e77b | 1095 | { |
e07d4801 | 1096 | DEBUG_puts("9ppd_test_constraints: NO"); |
e78998df | 1097 | break; |
06d4e77b | 1098 | } |
e78998df MS |
1099 | } |
1100 | else if (constptr->choice) | |
1101 | { | |
e60ec91f MS |
1102 | /* |
1103 | * Compare against the constrained choice... | |
1104 | */ | |
1105 | ||
88f9aafc | 1106 | if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword)) |
06d4e77b | 1107 | { |
88f9aafc | 1108 | if (!_cups_strncasecmp(choice, "Custom.", 7)) |
d1c13e16 MS |
1109 | value = "Custom"; |
1110 | else | |
1111 | value = choice; | |
06d4e77b MS |
1112 | } |
1113 | else if ((value = cupsGetOption(constptr->option->keyword, num_options, | |
1114 | options)) != NULL) | |
e78998df | 1115 | { |
88f9aafc | 1116 | if (!_cups_strncasecmp(value, "Custom.", 7)) |
d1c13e16 | 1117 | value = "Custom"; |
e60ec91f MS |
1118 | } |
1119 | else if (constptr->choice->marked) | |
1120 | value = constptr->choice->choice; | |
1121 | else | |
1122 | value = NULL; | |
d1c13e16 | 1123 | |
e60ec91f MS |
1124 | /* |
1125 | * Now check AP_FIRSTPAGE_option... | |
1126 | */ | |
1127 | ||
1128 | snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", | |
1129 | constptr->option->keyword); | |
1130 | ||
88f9aafc | 1131 | if (option && choice && !_cups_strcasecmp(option, firstpage)) |
e60ec91f | 1132 | { |
88f9aafc | 1133 | if (!_cups_strncasecmp(choice, "Custom.", 7)) |
e60ec91f MS |
1134 | firstvalue = "Custom"; |
1135 | else | |
1136 | firstvalue = choice; | |
1137 | } | |
1138 | else if ((firstvalue = cupsGetOption(firstpage, num_options, | |
1139 | options)) != NULL) | |
1140 | { | |
88f9aafc | 1141 | if (!_cups_strncasecmp(firstvalue, "Custom.", 7)) |
e60ec91f | 1142 | firstvalue = "Custom"; |
e78998df | 1143 | } |
e60ec91f MS |
1144 | else |
1145 | firstvalue = NULL; | |
1146 | ||
1147 | DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value, | |
1148 | firstvalue)); | |
1149 | ||
88f9aafc MS |
1150 | if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) && |
1151 | (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice))) | |
06d4e77b | 1152 | { |
e07d4801 | 1153 | DEBUG_puts("9ppd_test_constraints: NO"); |
06d4e77b MS |
1154 | break; |
1155 | } | |
1156 | } | |
1157 | else if (option && choice && | |
88f9aafc | 1158 | !_cups_strcasecmp(option, constptr->option->keyword)) |
06d4e77b | 1159 | { |
88f9aafc MS |
1160 | if (!_cups_strcasecmp(choice, "None") || !_cups_strcasecmp(choice, "Off") || |
1161 | !_cups_strcasecmp(choice, "False")) | |
d1c13e16 | 1162 | { |
e07d4801 | 1163 | DEBUG_puts("9ppd_test_constraints: NO"); |
e60ec91f | 1164 | break; |
d1c13e16 | 1165 | } |
e78998df MS |
1166 | } |
1167 | else if ((value = cupsGetOption(constptr->option->keyword, num_options, | |
e60ec91f | 1168 | options)) != NULL) |
e78998df | 1169 | { |
88f9aafc MS |
1170 | if (!_cups_strcasecmp(value, "None") || !_cups_strcasecmp(value, "Off") || |
1171 | !_cups_strcasecmp(value, "False")) | |
06d4e77b | 1172 | { |
e07d4801 | 1173 | DEBUG_puts("9ppd_test_constraints: NO"); |
06d4e77b MS |
1174 | break; |
1175 | } | |
e78998df MS |
1176 | } |
1177 | else | |
1178 | { | |
e60ec91f | 1179 | key.option = constptr->option; |
e78998df MS |
1180 | |
1181 | if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) | |
e60ec91f | 1182 | == NULL || |
88f9aafc MS |
1183 | (!_cups_strcasecmp(marked->choice, "None") || |
1184 | !_cups_strcasecmp(marked->choice, "Off") || | |
1185 | !_cups_strcasecmp(marked->choice, "False"))) | |
06d4e77b | 1186 | { |
e07d4801 | 1187 | DEBUG_puts("9ppd_test_constraints: NO"); |
e78998df | 1188 | break; |
06d4e77b | 1189 | } |
e78998df MS |
1190 | } |
1191 | } | |
1192 | ||
d1c13e16 | 1193 | if (i <= 0) |
e78998df MS |
1194 | { |
1195 | if (!active) | |
1196 | active = cupsArrayNew(NULL, NULL); | |
1197 | ||
1198 | cupsArrayAdd(active, consts); | |
e07d4801 | 1199 | DEBUG_puts("9ppd_test_constraints: Added..."); |
e78998df MS |
1200 | } |
1201 | } | |
1202 | ||
1203 | cupsArrayRestore(ppd->marked); | |
1204 | ||
e07d4801 | 1205 | DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!", |
06d4e77b MS |
1206 | cupsArrayCount(active))); |
1207 | ||
e78998df MS |
1208 | return (active); |
1209 | } | |
1210 | ||
1211 | ||
1212 | /* | |
1213 | * End of "$Id$". | |
1214 | */ |