]>
Commit | Line | Data |
---|---|---|
e78998df | 1 | /* |
f787e1e3 | 2 | * Option conflict management routines for CUPS. |
e78998df | 3 | * |
f787e1e3 | 4 | * Copyright 2007-2015 by Apple Inc. |
7e86f2f6 | 5 | * Copyright 1997-2007 by Easy Software Products, all rights reserved. |
e78998df | 6 | * |
7e86f2f6 MS |
7 | * These coded instructions, statements, and computer programs are the |
8 | * property of Apple Inc. and are protected by Federal copyright | |
9 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
10 | * which should have been included with this file. If this file is | |
11 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
e78998df | 12 | * |
7e86f2f6 | 13 | * PostScript is a trademark of Adobe Systems, Inc. |
e78998df | 14 | * |
7e86f2f6 | 15 | * This file is subject to the Apple OS-Developed Software exception. |
e78998df MS |
16 | */ |
17 | ||
18 | /* | |
19 | * Include necessary headers... | |
20 | */ | |
21 | ||
71e16022 | 22 | #include "cups-private.h" |
e78998df | 23 | #include "ppd-private.h" |
e78998df MS |
24 | |
25 | ||
26 | /* | |
27 | * Local constants... | |
28 | */ | |
29 | ||
30 | enum | |
31 | { | |
32 | _PPD_NORMAL_CONSTRAINTS, | |
e07d4801 | 33 | _PPD_OPTION_CONSTRAINTS, |
e78998df MS |
34 | _PPD_INSTALLABLE_CONSTRAINTS, |
35 | _PPD_ALL_CONSTRAINTS | |
36 | }; | |
37 | ||
38 | ||
39 | /* | |
40 | * Local functions... | |
41 | */ | |
42 | ||
43 | static int ppd_is_installable(ppd_group_t *installable, | |
44 | const char *option); | |
45 | static void ppd_load_constraints(ppd_file_t *ppd); | |
06d4e77b MS |
46 | static cups_array_t *ppd_test_constraints(ppd_file_t *ppd, |
47 | const char *option, | |
48 | const char *choice, | |
49 | int num_options, | |
e78998df MS |
50 | cups_option_t *options, |
51 | int which); | |
52 | ||
53 | ||
d2354e63 MS |
54 | /* |
55 | * 'cupsGetConflicts()' - Get a list of conflicting options in a marked PPD. | |
56 | * | |
57 | * This function gets a list of options that would conflict if "option" and | |
58 | * "choice" were marked in the PPD. You would typically call this function | |
59 | * after marking the currently selected options in the PPD in order to | |
60 | * determine whether a new option selection would cause a conflict. | |
61 | * | |
62 | * The number of conflicting options are returned with "options" pointing to | |
63 | * the conflicting options. The returned option array must be freed using | |
64 | * @link cupsFreeOptions@. | |
65 | * | |
8072030b | 66 | * @since CUPS 1.4/macOS 10.6@ |
d2354e63 MS |
67 | */ |
68 | ||
69 | int /* O - Number of conflicting options */ | |
70 | cupsGetConflicts( | |
71 | ppd_file_t *ppd, /* I - PPD file */ | |
72 | const char *option, /* I - Option to test */ | |
73 | const char *choice, /* I - Choice to test */ | |
74 | cups_option_t **options) /* O - Conflicting options */ | |
75 | { | |
76 | int i, /* Looping var */ | |
77 | num_options; /* Number of conflicting options */ | |
78 | cups_array_t *active; /* Active conflicts */ | |
79 | _ppd_cups_uiconsts_t *c; /* Current constraints */ | |
80 | _ppd_cups_uiconst_t *cptr; /* Current constraint */ | |
07ed0e9a | 81 | ppd_choice_t *marked; /* Marked choice */ |
d2354e63 MS |
82 | |
83 | ||
84 | /* | |
85 | * Range check input... | |
86 | */ | |
87 | ||
88 | if (options) | |
89 | *options = NULL; | |
90 | ||
91 | if (!ppd || !option || !choice || !options) | |
92 | return (0); | |
93 | ||
94 | /* | |
95 | * Test for conflicts... | |
96 | */ | |
97 | ||
98 | active = ppd_test_constraints(ppd, option, choice, 0, NULL, | |
99 | _PPD_ALL_CONSTRAINTS); | |
100 | ||
101 | /* | |
102 | * Loop through all of the UI constraints and add any options that conflict... | |
103 | */ | |
104 | ||
105 | for (num_options = 0, c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active); | |
106 | c; | |
107 | c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active)) | |
108 | { | |
109 | for (i = c->num_constraints, cptr = c->constraints; | |
110 | i > 0; | |
111 | i --, cptr ++) | |
88f9aafc | 112 | if (_cups_strcasecmp(cptr->option->keyword, option)) |
07ed0e9a MS |
113 | { |
114 | if (cptr->choice) | |
115 | num_options = cupsAddOption(cptr->option->keyword, | |
116 | cptr->choice->choice, num_options, | |
117 | options); | |
118 | else if ((marked = ppdFindMarkedChoice(ppd, | |
119 | cptr->option->keyword)) != NULL) | |
120 | num_options = cupsAddOption(cptr->option->keyword, marked->choice, | |
121 | num_options, options); | |
122 | } | |
d2354e63 MS |
123 | } |
124 | ||
125 | cupsArrayDelete(active); | |
126 | ||
127 | return (num_options); | |
128 | } | |
129 | ||
130 | ||
e78998df MS |
131 | /* |
132 | * 'cupsResolveConflicts()' - Resolve conflicts in a marked PPD. | |
133 | * | |
134 | * This function attempts to resolve any conflicts in a marked PPD, returning | |
06d4e77b MS |
135 | * a list of option changes that are required to resolve them. On input, |
136 | * "num_options" and "options" contain any pending option changes that have | |
137 | * not yet been marked, while "option" and "choice" contain the most recent | |
e78998df MS |
138 | * selection which may or may not be in "num_options" or "options". |
139 | * | |
140 | * On successful return, "num_options" and "options" are updated to contain | |
141 | * "option" and "choice" along with any changes required to resolve conflicts | |
06d4e77b MS |
142 | * specified in the PPD file and 1 is returned. |
143 | * | |
144 | * If option conflicts cannot be resolved, "num_options" and "options" are not | |
145 | * changed and 0 is returned. | |
e78998df | 146 | * |
06d4e77b MS |
147 | * When resolving conflicts, @code cupsResolveConflicts@ does not consider |
148 | * changes to the current page size (@code media@, @code PageSize@, and | |
149 | * @code PageRegion@) or to the most recent option specified in "option". | |
150 | * Thus, if the only way to resolve a conflict is to change the page size | |
151 | * or the option the user most recently changed, @code cupsResolveConflicts@ | |
152 | * will return 0 to indicate it was unable to resolve the conflicts. | |
153 | * | |
154 | * The @code cupsResolveConflicts@ function uses one of two sources of option | |
155 | * constraint information. The preferred constraint information is defined by | |
e78998df | 156 | * @code cupsUIConstraints@ and @code cupsUIResolver@ attributes - in this |
06d4e77b | 157 | * case, the PPD file provides constraint resolution actions. |
e78998df | 158 | * |
06d4e77b | 159 | * The backup constraint information is defined by the |
e78998df | 160 | * @code UIConstraints@ and @code NonUIConstraints@ attributes. These |
06d4e77b MS |
161 | * constraints are resolved algorithmically by first selecting the default |
162 | * choice for the conflicting option, then iterating over all possible choices | |
163 | * until a non-conflicting option choice is found. | |
e78998df | 164 | * |
8072030b | 165 | * @since CUPS 1.4/macOS 10.6@ |
e78998df MS |
166 | */ |
167 | ||
168 | int /* O - 1 on success, 0 on failure */ | |
169 | cupsResolveConflicts( | |
170 | ppd_file_t *ppd, /* I - PPD file */ | |
171 | const char *option, /* I - Newly selected option or @code NULL@ for none */ | |
172 | const char *choice, /* I - Newly selected choice or @code NULL@ for none */ | |
173 | int *num_options, /* IO - Number of additional selected options */ | |
174 | cups_option_t **options) /* IO - Additional selected options */ | |
175 | { | |
176 | int i, /* Looping var */ | |
b0f6947b | 177 | tries, /* Number of tries */ |
1340db2d MS |
178 | num_newopts; /* Number of new options */ |
179 | cups_option_t *newopts; /* New options */ | |
7e86f2f6 | 180 | cups_array_t *active = NULL, /* Active constraints */ |
e78998df | 181 | *pass, /* Resolvers for this pass */ |
1340db2d MS |
182 | *resolvers, /* Resolvers we have used */ |
183 | *test; /* Test array for conflicts */ | |
e78998df MS |
184 | _ppd_cups_uiconsts_t *consts; /* Current constraints */ |
185 | _ppd_cups_uiconst_t *constptr; /* Current constraint */ | |
186 | ppd_attr_t *resolver; /* Current resolver */ | |
1340db2d MS |
187 | const char *resval; /* Pointer into resolver value */ |
188 | char resoption[PPD_MAX_NAME], | |
189 | /* Current resolver option */ | |
190 | reschoice[PPD_MAX_NAME], | |
191 | /* Current resolver choice */ | |
e60ec91f MS |
192 | *resptr, /* Pointer into option/choice */ |
193 | firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ | |
e78998df MS |
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); | |
88f9aafc | 216 | if (option && _cups_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; | |
88f9aafc | 226 | pass = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); |
b0f6947b | 227 | tries = 0; |
e78998df | 228 | |
b0f6947b MS |
229 | while (tries < 100 && |
230 | (active = ppd_test_constraints(ppd, NULL, NULL, num_newopts, newopts, | |
e78998df MS |
231 | _PPD_ALL_CONSTRAINTS)) != NULL) |
232 | { | |
b0f6947b MS |
233 | tries ++; |
234 | ||
e78998df | 235 | if (!resolvers) |
88f9aafc | 236 | resolvers = cupsArrayNew((cups_array_func_t)_cups_strcasecmp, NULL); |
e78998df MS |
237 | |
238 | for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active), changed = 0; | |
239 | consts; | |
240 | consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(active)) | |
241 | { | |
242 | if (consts->resolver[0]) | |
243 | { | |
244 | /* | |
245 | * Look up the resolver... | |
246 | */ | |
247 | ||
248 | if (cupsArrayFind(pass, consts->resolver)) | |
249 | continue; /* Already applied this resolver... */ | |
250 | ||
251 | if (cupsArrayFind(resolvers, consts->resolver)) | |
252 | { | |
253 | /* | |
254 | * Resolver loop! | |
255 | */ | |
256 | ||
f99f3698 | 257 | DEBUG_printf(("1cupsResolveConflicts: Resolver loop with %s!", |
e78998df MS |
258 | consts->resolver)); |
259 | goto error; | |
260 | } | |
261 | ||
262 | if ((resolver = ppdFindAttr(ppd, "cupsUIResolver", | |
263 | consts->resolver)) == NULL) | |
264 | { | |
f99f3698 | 265 | DEBUG_printf(("1cupsResolveConflicts: Resolver %s not found!", |
e78998df MS |
266 | consts->resolver)); |
267 | goto error; | |
268 | } | |
269 | ||
270 | if (!resolver->value) | |
271 | { | |
f99f3698 | 272 | DEBUG_printf(("1cupsResolveConflicts: Resolver %s has no value!", |
e78998df MS |
273 | consts->resolver)); |
274 | goto error; | |
275 | } | |
276 | ||
277 | /* | |
278 | * Add the options from the resolver... | |
279 | */ | |
280 | ||
281 | cupsArrayAdd(pass, consts->resolver); | |
282 | cupsArrayAdd(resolvers, consts->resolver); | |
283 | ||
1340db2d | 284 | for (resval = resolver->value; *resval && !changed;) |
06d4e77b | 285 | { |
7cf5915e | 286 | while (_cups_isspace(*resval)) |
1340db2d | 287 | resval ++; |
06d4e77b | 288 | |
1340db2d MS |
289 | if (*resval != '*') |
290 | break; | |
291 | ||
292 | for (resval ++, resptr = resoption; | |
7cf5915e | 293 | *resval && !_cups_isspace(*resval); |
1340db2d MS |
294 | resval ++) |
295 | if (resptr < (resoption + sizeof(resoption) - 1)) | |
296 | *resptr++ = *resval; | |
297 | ||
298 | *resptr = '\0'; | |
299 | ||
7cf5915e | 300 | while (_cups_isspace(*resval)) |
1340db2d MS |
301 | resval ++; |
302 | ||
303 | for (resptr = reschoice; | |
7cf5915e | 304 | *resval && !_cups_isspace(*resval); |
1340db2d MS |
305 | resval ++) |
306 | if (resptr < (reschoice + sizeof(reschoice) - 1)) | |
307 | *resptr++ = *resval; | |
308 | ||
309 | *resptr = '\0'; | |
310 | ||
311 | if (!resoption[0] || !reschoice[0]) | |
312 | break; | |
313 | ||
314 | /* | |
315 | * Is this the option we are changing? | |
316 | */ | |
317 | ||
e60ec91f MS |
318 | snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", resoption); |
319 | ||
1340db2d | 320 | if (option && |
88f9aafc MS |
321 | (!_cups_strcasecmp(resoption, option) || |
322 | !_cups_strcasecmp(firstpage, option) || | |
323 | (!_cups_strcasecmp(option, "PageSize") && | |
324 | !_cups_strcasecmp(resoption, "PageRegion")) || | |
325 | (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && | |
326 | !_cups_strcasecmp(resoption, "PageSize")) || | |
327 | (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") && | |
328 | !_cups_strcasecmp(resoption, "PageRegion")) || | |
329 | (!_cups_strcasecmp(option, "PageRegion") && | |
330 | !_cups_strcasecmp(resoption, "PageSize")) || | |
331 | (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && | |
332 | !_cups_strcasecmp(resoption, "PageSize")) || | |
333 | (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion") && | |
334 | !_cups_strcasecmp(resoption, "PageRegion")))) | |
1340db2d MS |
335 | continue; |
336 | ||
337 | /* | |
338 | * Try this choice... | |
339 | */ | |
340 | ||
341 | if ((test = ppd_test_constraints(ppd, resoption, reschoice, | |
342 | num_newopts, newopts, | |
343 | _PPD_ALL_CONSTRAINTS)) == NULL) | |
06d4e77b | 344 | { |
1340db2d MS |
345 | /* |
346 | * That worked... | |
347 | */ | |
06d4e77b | 348 | |
1340db2d MS |
349 | changed = 1; |
350 | } | |
351 | else | |
352 | cupsArrayDelete(test); | |
06d4e77b | 353 | |
1340db2d MS |
354 | /* |
355 | * Add the option/choice from the resolver regardless of whether it | |
356 | * worked; this makes sure that we can cascade several changes to | |
357 | * make things resolve... | |
358 | */ | |
359 | ||
360 | num_newopts = cupsAddOption(resoption, reschoice, num_newopts, | |
361 | &newopts); | |
362 | } | |
e78998df MS |
363 | } |
364 | else | |
365 | { | |
366 | /* | |
367 | * Try resolving by choosing the default values for non-installable | |
06d4e77b | 368 | * options, then by iterating through the possible choices... |
e78998df MS |
369 | */ |
370 | ||
06d4e77b MS |
371 | int j; /* Looping var */ |
372 | ppd_choice_t *cptr; /* Current choice */ | |
d1c13e16 | 373 | ppd_size_t *size; /* Current page size */ |
06d4e77b MS |
374 | |
375 | ||
376 | for (i = consts->num_constraints, constptr = consts->constraints; | |
c168a833 | 377 | i > 0 && !changed; |
e78998df MS |
378 | i --, constptr ++) |
379 | { | |
c168a833 MS |
380 | /* |
381 | * Can't resolve by changing an installable option... | |
382 | */ | |
383 | ||
384 | if (constptr->installable) | |
e78998df MS |
385 | continue; |
386 | ||
c168a833 MS |
387 | /* |
388 | * Is this the option we are changing? | |
389 | */ | |
390 | ||
d1c13e16 | 391 | if (option && |
88f9aafc MS |
392 | (!_cups_strcasecmp(constptr->option->keyword, option) || |
393 | (!_cups_strcasecmp(option, "PageSize") && | |
394 | !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) || | |
395 | (!_cups_strcasecmp(option, "PageRegion") && | |
396 | !_cups_strcasecmp(constptr->option->keyword, "PageSize")))) | |
e78998df | 397 | continue; |
e78998df | 398 | |
c168a833 MS |
399 | /* |
400 | * Get the current option choice... | |
401 | */ | |
402 | ||
e78998df MS |
403 | if ((value = cupsGetOption(constptr->option->keyword, num_newopts, |
404 | newopts)) == NULL) | |
405 | { | |
88f9aafc MS |
406 | if (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || |
407 | !_cups_strcasecmp(constptr->option->keyword, "PageRegion")) | |
d1c13e16 MS |
408 | { |
409 | if ((value = cupsGetOption("PageSize", num_newopts, | |
410 | newopts)) == NULL) | |
411 | value = cupsGetOption("PageRegion", num_newopts, newopts); | |
412 | ||
413 | if (!value) | |
414 | { | |
415 | if ((size = ppdPageSize(ppd, NULL)) != NULL) | |
416 | value = size->name; | |
417 | else | |
418 | value = ""; | |
419 | } | |
420 | } | |
421 | else | |
422 | { | |
423 | marked = ppdFindMarkedChoice(ppd, constptr->option->keyword); | |
424 | value = marked ? marked->choice : ""; | |
425 | } | |
e78998df MS |
426 | } |
427 | ||
88f9aafc | 428 | if (!_cups_strncasecmp(value, "Custom.", 7)) |
d1c13e16 MS |
429 | value = "Custom"; |
430 | ||
06d4e77b MS |
431 | /* |
432 | * Try the default choice... | |
e78998df MS |
433 | */ |
434 | ||
06d4e77b | 435 | test = NULL; |
e78998df | 436 | |
88f9aafc | 437 | if (_cups_strcasecmp(value, constptr->option->defchoice) && |
06d4e77b MS |
438 | (test = ppd_test_constraints(ppd, constptr->option->keyword, |
439 | constptr->option->defchoice, | |
440 | num_newopts, newopts, | |
e07d4801 | 441 | _PPD_OPTION_CONSTRAINTS)) == NULL) |
e78998df | 442 | { |
06d4e77b MS |
443 | /* |
444 | * That worked... | |
445 | */ | |
446 | ||
447 | num_newopts = cupsAddOption(constptr->option->keyword, | |
448 | constptr->option->defchoice, | |
e78998df MS |
449 | num_newopts, &newopts); |
450 | changed = 1; | |
451 | } | |
06d4e77b MS |
452 | else |
453 | { | |
454 | /* | |
455 | * Try each choice instead... | |
456 | */ | |
457 | ||
06d4e77b MS |
458 | for (j = constptr->option->num_choices, |
459 | cptr = constptr->option->choices; | |
460 | j > 0; | |
461 | j --, cptr ++) | |
462 | { | |
c168a833 | 463 | cupsArrayDelete(test); |
06d4e77b MS |
464 | test = NULL; |
465 | ||
88f9aafc MS |
466 | if (_cups_strcasecmp(value, cptr->choice) && |
467 | _cups_strcasecmp(constptr->option->defchoice, cptr->choice) && | |
468 | _cups_strcasecmp("Custom", cptr->choice) && | |
06d4e77b MS |
469 | (test = ppd_test_constraints(ppd, constptr->option->keyword, |
470 | cptr->choice, num_newopts, | |
471 | newopts, | |
e07d4801 | 472 | _PPD_OPTION_CONSTRAINTS)) == NULL) |
06d4e77b MS |
473 | { |
474 | /* | |
475 | * This choice works... | |
476 | */ | |
477 | ||
478 | num_newopts = cupsAddOption(constptr->option->keyword, | |
479 | cptr->choice, num_newopts, | |
480 | &newopts); | |
481 | changed = 1; | |
482 | break; | |
483 | } | |
06d4e77b | 484 | } |
c168a833 MS |
485 | |
486 | cupsArrayDelete(test); | |
06d4e77b MS |
487 | } |
488 | } | |
e78998df | 489 | } |
0268488e | 490 | } |
e78998df | 491 | |
0268488e MS |
492 | if (!changed) |
493 | { | |
f99f3698 | 494 | DEBUG_puts("1cupsResolveConflicts: Unable to automatically resolve " |
0268488e MS |
495 | "constraint!"); |
496 | goto error; | |
e78998df MS |
497 | } |
498 | ||
499 | cupsArrayClear(pass); | |
500 | cupsArrayDelete(active); | |
b0f6947b | 501 | active = NULL; |
e78998df MS |
502 | } |
503 | ||
b0f6947b MS |
504 | if (tries >= 100) |
505 | goto error; | |
506 | ||
e78998df | 507 | /* |
005dd1eb | 508 | * Free the caller's option array... |
e78998df MS |
509 | */ |
510 | ||
005dd1eb MS |
511 | cupsFreeOptions(*num_options, *options); |
512 | ||
513 | /* | |
514 | * If Collate is the option we are testing, add it here. Otherwise, remove | |
515 | * any Collate option from the resolve list since the filters automatically | |
516 | * handle manual collation... | |
517 | */ | |
518 | ||
88f9aafc | 519 | if (option && !_cups_strcasecmp(option, "Collate")) |
005dd1eb | 520 | num_newopts = cupsAddOption(option, choice, num_newopts, &newopts); |
e78998df | 521 | else |
005dd1eb MS |
522 | num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts); |
523 | ||
524 | /* | |
525 | * Return the new list of options to the caller... | |
526 | */ | |
527 | ||
528 | *num_options = num_newopts; | |
529 | *options = newopts; | |
e78998df MS |
530 | |
531 | cupsArrayDelete(pass); | |
532 | cupsArrayDelete(resolvers); | |
533 | ||
534 | cupsArrayRestore(ppd->sorted_attrs); | |
535 | ||
e07d4801 | 536 | DEBUG_printf(("1cupsResolveConflicts: Returning %d options:", num_newopts)); |
d1c13e16 MS |
537 | #ifdef DEBUG |
538 | for (i = 0; i < num_newopts; i ++) | |
e07d4801 | 539 | DEBUG_printf(("1cupsResolveConflicts: options[%d]: %s=%s", i, |
d1c13e16 MS |
540 | newopts[i].name, newopts[i].value)); |
541 | #endif /* DEBUG */ | |
542 | ||
e78998df MS |
543 | return (1); |
544 | ||
545 | /* | |
546 | * If we get here, we failed to resolve... | |
547 | */ | |
548 | ||
549 | error: | |
550 | ||
551 | cupsFreeOptions(num_newopts, newopts); | |
552 | ||
94da7e34 | 553 | cupsArrayDelete(active); |
e78998df MS |
554 | cupsArrayDelete(pass); |
555 | cupsArrayDelete(resolvers); | |
556 | ||
557 | cupsArrayRestore(ppd->sorted_attrs); | |
558 | ||
e07d4801 | 559 | DEBUG_puts("1cupsResolveConflicts: Unable to resolve conflicts!"); |
d1c13e16 | 560 | |
e78998df MS |
561 | return (0); |
562 | } | |
563 | ||
564 | ||
06d4e77b MS |
565 | /* |
566 | * 'ppdConflicts()' - Check to see if there are any conflicts among the | |
567 | * marked option choices. | |
568 | * | |
569 | * The returned value is the same as returned by @link ppdMarkOption@. | |
570 | */ | |
571 | ||
572 | int /* O - Number of conflicts found */ | |
573 | ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */ | |
574 | { | |
575 | int i, /* Looping variable */ | |
576 | conflicts; /* Number of conflicts */ | |
577 | cups_array_t *active; /* Active conflicts */ | |
578 | _ppd_cups_uiconsts_t *c; /* Current constraints */ | |
579 | _ppd_cups_uiconst_t *cptr; /* Current constraint */ | |
580 | ppd_option_t *o; /* Current option */ | |
581 | ||
582 | ||
583 | if (!ppd) | |
584 | return (0); | |
585 | ||
586 | /* | |
587 | * Clear all conflicts... | |
588 | */ | |
589 | ||
ef55b745 MS |
590 | cupsArraySave(ppd->options); |
591 | ||
06d4e77b MS |
592 | for (o = ppdFirstOption(ppd); o; o = ppdNextOption(ppd)) |
593 | o->conflicted = 0; | |
594 | ||
ef55b745 MS |
595 | cupsArrayRestore(ppd->options); |
596 | ||
06d4e77b MS |
597 | /* |
598 | * Test for conflicts... | |
599 | */ | |
600 | ||
601 | active = ppd_test_constraints(ppd, NULL, NULL, 0, NULL, | |
602 | _PPD_ALL_CONSTRAINTS); | |
603 | conflicts = cupsArrayCount(active); | |
604 | ||
605 | /* | |
606 | * Loop through all of the UI constraints and flag any options | |
607 | * that conflict... | |
608 | */ | |
609 | ||
610 | for (c = (_ppd_cups_uiconsts_t *)cupsArrayFirst(active); | |
611 | c; | |
612 | c = (_ppd_cups_uiconsts_t *)cupsArrayNext(active)) | |
613 | { | |
614 | for (i = c->num_constraints, cptr = c->constraints; | |
615 | i > 0; | |
616 | i --, cptr ++) | |
617 | cptr->option->conflicted = 1; | |
618 | } | |
619 | ||
620 | cupsArrayDelete(active); | |
621 | ||
622 | /* | |
623 | * Return the number of conflicts found... | |
624 | */ | |
625 | ||
626 | return (conflicts); | |
627 | } | |
628 | ||
629 | ||
630 | /* | |
631 | * 'ppdInstallableConflict()' - Test whether an option choice conflicts with | |
632 | * an installable option. | |
633 | * | |
634 | * This function tests whether a particular option choice is available based | |
635 | * on constraints against options in the "InstallableOptions" group. | |
636 | * | |
8072030b | 637 | * @since CUPS 1.4/macOS 10.6@ |
06d4e77b MS |
638 | */ |
639 | ||
640 | int /* O - 1 if conflicting, 0 if not conflicting */ | |
641 | ppdInstallableConflict( | |
642 | ppd_file_t *ppd, /* I - PPD file */ | |
643 | const char *option, /* I - Option */ | |
644 | const char *choice) /* I - Choice */ | |
645 | { | |
646 | cups_array_t *active; /* Active conflicts */ | |
647 | ||
648 | ||
e07d4801 MS |
649 | DEBUG_printf(("2ppdInstallableConflict(ppd=%p, option=\"%s\", choice=\"%s\")", |
650 | ppd, option, choice)); | |
651 | ||
ef55b745 | 652 | /* |
06d4e77b MS |
653 | * Range check input... |
654 | */ | |
655 | ||
656 | if (!ppd || !option || !choice) | |
657 | return (0); | |
658 | ||
659 | /* | |
660 | * Test constraints using the new option... | |
661 | */ | |
662 | ||
663 | active = ppd_test_constraints(ppd, option, choice, 0, NULL, | |
664 | _PPD_INSTALLABLE_CONSTRAINTS); | |
665 | ||
666 | cupsArrayDelete(active); | |
667 | ||
668 | return (active != NULL); | |
669 | } | |
670 | ||
671 | ||
e78998df MS |
672 | /* |
673 | * 'ppd_is_installable()' - Determine whether an option is in the | |
674 | * InstallableOptions group. | |
675 | */ | |
676 | ||
677 | static int /* O - 1 if installable, 0 if normal */ | |
678 | ppd_is_installable( | |
679 | ppd_group_t *installable, /* I - InstallableOptions group */ | |
680 | const char *name) /* I - Option name */ | |
681 | { | |
682 | if (installable) | |
683 | { | |
684 | int i; /* Looping var */ | |
685 | ppd_option_t *option; /* Current option */ | |
686 | ||
687 | ||
688 | for (i = installable->num_options, option = installable->options; | |
689 | i > 0; | |
690 | i --, option ++) | |
88f9aafc | 691 | if (!_cups_strcasecmp(option->keyword, name)) |
e78998df MS |
692 | return (1); |
693 | } | |
694 | ||
695 | return (0); | |
696 | } | |
697 | ||
698 | ||
699 | /* | |
700 | * 'ppd_load_constraints()' - Load constraints from a PPD file. | |
701 | */ | |
702 | ||
703 | static void | |
704 | ppd_load_constraints(ppd_file_t *ppd) /* I - PPD file */ | |
705 | { | |
706 | int i; /* Looping var */ | |
707 | ppd_const_t *oldconst; /* Current UIConstraints data */ | |
708 | ppd_attr_t *constattr; /* Current cupsUIConstraints attribute */ | |
709 | _ppd_cups_uiconsts_t *consts; /* Current cupsUIConstraints data */ | |
710 | _ppd_cups_uiconst_t *constptr; /* Current constraint */ | |
711 | ppd_group_t *installable; /* Installable options group */ | |
712 | const char *vptr; /* Pointer into constraint value */ | |
713 | char option[PPD_MAX_NAME], /* Option name/MainKeyword */ | |
714 | choice[PPD_MAX_NAME], /* Choice/OptionKeyword */ | |
715 | *ptr; /* Pointer into option or choice */ | |
716 | ||
717 | ||
e07d4801 MS |
718 | DEBUG_printf(("7ppd_load_constraints(ppd=%p)", ppd)); |
719 | ||
e78998df MS |
720 | /* |
721 | * Create an array to hold the constraint data... | |
722 | */ | |
723 | ||
724 | ppd->cups_uiconstraints = cupsArrayNew(NULL, NULL); | |
725 | ||
726 | /* | |
727 | * Find the installable options group if it exists... | |
728 | */ | |
729 | ||
730 | for (i = ppd->num_groups, installable = ppd->groups; | |
731 | i > 0; | |
732 | i --, installable ++) | |
88f9aafc | 733 | if (!_cups_strcasecmp(installable->name, "InstallableOptions")) |
e78998df MS |
734 | break; |
735 | ||
736 | if (i <= 0) | |
737 | installable = NULL; | |
738 | ||
739 | /* | |
28b9d139 | 740 | * Load old-style [Non]UIConstraints data... |
e78998df MS |
741 | */ |
742 | ||
28b9d139 | 743 | for (i = ppd->num_consts, oldconst = ppd->consts; i > 0; i --, oldconst ++) |
e78998df MS |
744 | { |
745 | /* | |
28b9d139 MS |
746 | * Weed out nearby duplicates, since the PPD spec requires that you |
747 | * define both "*Foo foo *Bar bar" and "*Bar bar *Foo foo"... | |
e78998df MS |
748 | */ |
749 | ||
28b9d139 | 750 | if (i > 1 && |
88f9aafc MS |
751 | !_cups_strcasecmp(oldconst[0].option1, oldconst[1].option2) && |
752 | !_cups_strcasecmp(oldconst[0].choice1, oldconst[1].choice2) && | |
753 | !_cups_strcasecmp(oldconst[0].option2, oldconst[1].option1) && | |
754 | !_cups_strcasecmp(oldconst[0].choice2, oldconst[1].choice1)) | |
28b9d139 | 755 | continue; |
e78998df | 756 | |
28b9d139 MS |
757 | /* |
758 | * Allocate memory... | |
759 | */ | |
e78998df | 760 | |
28b9d139 MS |
761 | if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) |
762 | { | |
e07d4801 | 763 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
764 | "UIConstraints!"); |
765 | return; | |
766 | } | |
e78998df | 767 | |
28b9d139 MS |
768 | if ((constptr = calloc(2, sizeof(_ppd_cups_uiconst_t))) == NULL) |
769 | { | |
770 | free(consts); | |
e07d4801 | 771 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
772 | "UIConstraints!"); |
773 | return; | |
774 | } | |
e78998df | 775 | |
28b9d139 MS |
776 | /* |
777 | * Fill in the information... | |
778 | */ | |
e78998df | 779 | |
28b9d139 MS |
780 | consts->num_constraints = 2; |
781 | consts->constraints = constptr; | |
e78998df | 782 | |
88f9aafc MS |
783 | if (!_cups_strncasecmp(oldconst->option1, "Custom", 6) && |
784 | !_cups_strcasecmp(oldconst->choice1, "True")) | |
28b9d139 MS |
785 | { |
786 | constptr[0].option = ppdFindOption(ppd, oldconst->option1 + 6); | |
787 | constptr[0].choice = ppdFindChoice(constptr[0].option, "Custom"); | |
788 | constptr[0].installable = 0; | |
789 | } | |
790 | else | |
791 | { | |
792 | constptr[0].option = ppdFindOption(ppd, oldconst->option1); | |
793 | constptr[0].choice = ppdFindChoice(constptr[0].option, | |
794 | oldconst->choice1); | |
795 | constptr[0].installable = ppd_is_installable(installable, | |
796 | oldconst->option1); | |
797 | } | |
e78998df | 798 | |
28b9d139 MS |
799 | if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0])) |
800 | { | |
e07d4801 | 801 | DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", |
28b9d139 MS |
802 | oldconst->option1, oldconst->choice1)); |
803 | free(consts->constraints); | |
804 | free(consts); | |
805 | continue; | |
806 | } | |
e78998df | 807 | |
88f9aafc MS |
808 | if (!_cups_strncasecmp(oldconst->option2, "Custom", 6) && |
809 | !_cups_strcasecmp(oldconst->choice2, "True")) | |
28b9d139 MS |
810 | { |
811 | constptr[1].option = ppdFindOption(ppd, oldconst->option2 + 6); | |
812 | constptr[1].choice = ppdFindChoice(constptr[1].option, "Custom"); | |
813 | constptr[1].installable = 0; | |
814 | } | |
815 | else | |
816 | { | |
817 | constptr[1].option = ppdFindOption(ppd, oldconst->option2); | |
818 | constptr[1].choice = ppdFindChoice(constptr[1].option, | |
819 | oldconst->choice2); | |
820 | constptr[1].installable = ppd_is_installable(installable, | |
821 | oldconst->option2); | |
822 | } | |
e78998df | 823 | |
28b9d139 MS |
824 | if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0])) |
825 | { | |
e07d4801 | 826 | DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", |
28b9d139 MS |
827 | oldconst->option2, oldconst->choice2)); |
828 | free(consts->constraints); | |
829 | free(consts); | |
830 | continue; | |
831 | } | |
e78998df | 832 | |
28b9d139 | 833 | consts->installable = constptr[0].installable || constptr[1].installable; |
e78998df | 834 | |
28b9d139 MS |
835 | /* |
836 | * Add it to the constraints array... | |
837 | */ | |
e78998df | 838 | |
28b9d139 MS |
839 | cupsArrayAdd(ppd->cups_uiconstraints, consts); |
840 | } | |
e78998df | 841 | |
28b9d139 MS |
842 | /* |
843 | * Then load new-style constraints... | |
844 | */ | |
e78998df | 845 | |
28b9d139 MS |
846 | for (constattr = ppdFindAttr(ppd, "cupsUIConstraints", NULL); |
847 | constattr; | |
848 | constattr = ppdFindNextAttr(ppd, "cupsUIConstraints", NULL)) | |
849 | { | |
850 | if (!constattr->value) | |
851 | { | |
e07d4801 | 852 | DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); |
28b9d139 MS |
853 | continue; |
854 | } | |
e78998df | 855 | |
28b9d139 MS |
856 | for (i = 0, vptr = strchr(constattr->value, '*'); |
857 | vptr; | |
858 | i ++, vptr = strchr(vptr + 1, '*')); | |
e78998df | 859 | |
28b9d139 MS |
860 | if (i == 0) |
861 | { | |
e07d4801 | 862 | DEBUG_puts("8ppd_load_constraints: Bad cupsUIConstraints value!"); |
28b9d139 | 863 | continue; |
e78998df | 864 | } |
e78998df | 865 | |
28b9d139 | 866 | if ((consts = calloc(1, sizeof(_ppd_cups_uiconsts_t))) == NULL) |
e78998df | 867 | { |
e07d4801 | 868 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
869 | "cupsUIConstraints!"); |
870 | return; | |
871 | } | |
e78998df | 872 | |
7e86f2f6 | 873 | if ((constptr = calloc((size_t)i, sizeof(_ppd_cups_uiconst_t))) == NULL) |
28b9d139 MS |
874 | { |
875 | free(consts); | |
e07d4801 | 876 | DEBUG_puts("8ppd_load_constraints: Unable to allocate memory for " |
28b9d139 MS |
877 | "cupsUIConstraints!"); |
878 | return; | |
879 | } | |
e78998df | 880 | |
28b9d139 MS |
881 | consts->num_constraints = i; |
882 | consts->constraints = constptr; | |
e78998df | 883 | |
28b9d139 | 884 | strlcpy(consts->resolver, constattr->spec, sizeof(consts->resolver)); |
e78998df | 885 | |
28b9d139 MS |
886 | for (i = 0, vptr = strchr(constattr->value, '*'); |
887 | vptr; | |
888 | i ++, vptr = strchr(vptr, '*'), constptr ++) | |
889 | { | |
e78998df | 890 | /* |
28b9d139 | 891 | * Extract "*Option Choice" or just "*Option"... |
e78998df MS |
892 | */ |
893 | ||
7cf5915e | 894 | for (vptr ++, ptr = option; *vptr && !_cups_isspace(*vptr); vptr ++) |
28b9d139 MS |
895 | if (ptr < (option + sizeof(option) - 1)) |
896 | *ptr++ = *vptr; | |
e78998df | 897 | |
28b9d139 | 898 | *ptr = '\0'; |
e78998df | 899 | |
7cf5915e | 900 | while (_cups_isspace(*vptr)) |
28b9d139 | 901 | vptr ++; |
e78998df | 902 | |
28b9d139 MS |
903 | if (*vptr == '*') |
904 | choice[0] = '\0'; | |
e78998df MS |
905 | else |
906 | { | |
7cf5915e | 907 | for (ptr = choice; *vptr && !_cups_isspace(*vptr); vptr ++) |
28b9d139 MS |
908 | if (ptr < (choice + sizeof(choice) - 1)) |
909 | *ptr++ = *vptr; | |
910 | ||
911 | *ptr = '\0'; | |
e78998df MS |
912 | } |
913 | ||
88f9aafc | 914 | if (!_cups_strncasecmp(option, "Custom", 6) && !_cups_strcasecmp(choice, "True")) |
e78998df | 915 | { |
28b9d139 | 916 | _cups_strcpy(option, option + 6); |
5a9febac | 917 | strlcpy(choice, "Custom", sizeof(choice)); |
e78998df MS |
918 | } |
919 | ||
28b9d139 MS |
920 | constptr->option = ppdFindOption(ppd, option); |
921 | constptr->choice = ppdFindChoice(constptr->option, choice); | |
922 | constptr->installable = ppd_is_installable(installable, option); | |
923 | consts->installable |= constptr->installable; | |
e78998df | 924 | |
28b9d139 MS |
925 | if (!constptr->option || (!constptr->choice && choice[0])) |
926 | { | |
e07d4801 | 927 | DEBUG_printf(("8ppd_load_constraints: Unknown option *%s %s!", |
28b9d139 MS |
928 | option, choice)); |
929 | break; | |
930 | } | |
931 | } | |
e78998df | 932 | |
28b9d139 | 933 | if (!vptr) |
e78998df | 934 | cupsArrayAdd(ppd->cups_uiconstraints, consts); |
28b9d139 MS |
935 | else |
936 | { | |
937 | free(consts->constraints); | |
938 | free(consts); | |
e78998df MS |
939 | } |
940 | } | |
941 | } | |
942 | ||
943 | ||
e78998df MS |
944 | /* |
945 | * 'ppd_test_constraints()' - See if any constraints are active. | |
946 | */ | |
947 | ||
948 | static cups_array_t * /* O - Array of active constraints */ | |
949 | ppd_test_constraints( | |
950 | ppd_file_t *ppd, /* I - PPD file */ | |
06d4e77b MS |
951 | const char *option, /* I - Current option */ |
952 | const char *choice, /* I - Current choice */ | |
e78998df MS |
953 | int num_options, /* I - Number of additional options */ |
954 | cups_option_t *options, /* I - Additional options */ | |
955 | int which) /* I - Which constraints to test */ | |
956 | { | |
957 | int i; /* Looping var */ | |
958 | _ppd_cups_uiconsts_t *consts; /* Current constraints */ | |
959 | _ppd_cups_uiconst_t *constptr; /* Current constraint */ | |
960 | ppd_choice_t key, /* Search key */ | |
961 | *marked; /* Marked choice */ | |
962 | cups_array_t *active = NULL; /* Active constraints */ | |
e60ec91f MS |
963 | const char *value, /* Current value */ |
964 | *firstvalue; /* AP_FIRSTPAGE_Keyword value */ | |
965 | char firstpage[255]; /* AP_FIRSTPAGE_Keyword string */ | |
06d4e77b | 966 | |
e78998df | 967 | |
e07d4801 MS |
968 | DEBUG_printf(("7ppd_test_constraints(ppd=%p, option=\"%s\", choice=\"%s\", " |
969 | "num_options=%d, options=%p, which=%d)", ppd, option, choice, | |
970 | num_options, options, which)); | |
e78998df MS |
971 | |
972 | if (!ppd->cups_uiconstraints) | |
973 | ppd_load_constraints(ppd); | |
974 | ||
e07d4801 | 975 | DEBUG_printf(("9ppd_test_constraints: %d constraints!", |
06d4e77b MS |
976 | cupsArrayCount(ppd->cups_uiconstraints))); |
977 | ||
e78998df MS |
978 | cupsArraySave(ppd->marked); |
979 | ||
980 | for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints); | |
981 | consts; | |
982 | consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints)) | |
983 | { | |
e07d4801 | 984 | DEBUG_printf(("9ppd_test_constraints: installable=%d, resolver=\"%s\", " |
06d4e77b | 985 | "num_constraints=%d option1=\"%s\", choice1=\"%s\", " |
e07d4801 | 986 | "option2=\"%s\", choice2=\"%s\", ...", |
06d4e77b MS |
987 | consts->installable, consts->resolver, consts->num_constraints, |
988 | consts->constraints[0].option->keyword, | |
989 | consts->constraints[0].choice ? | |
990 | consts->constraints[0].choice->choice : "", | |
991 | consts->constraints[1].option->keyword, | |
992 | consts->constraints[1].choice ? | |
993 | consts->constraints[1].choice->choice : "")); | |
994 | ||
e07d4801 MS |
995 | if (consts->installable && which < _PPD_INSTALLABLE_CONSTRAINTS) |
996 | continue; /* Skip installable option constraint */ | |
997 | ||
998 | if (!consts->installable && which == _PPD_INSTALLABLE_CONSTRAINTS) | |
999 | continue; /* Skip non-installable option constraint */ | |
1000 | ||
1001 | if (which == _PPD_OPTION_CONSTRAINTS && option) | |
1002 | { | |
1003 | /* | |
1004 | * Skip constraints that do not involve the current option... | |
1005 | */ | |
1006 | ||
1007 | for (i = consts->num_constraints, constptr = consts->constraints; | |
1008 | i > 0; | |
1009 | i --, constptr ++) | |
e60ec91f | 1010 | { |
88f9aafc | 1011 | if (!_cups_strcasecmp(constptr->option->keyword, option)) |
e07d4801 MS |
1012 | break; |
1013 | ||
88f9aafc MS |
1014 | if (!_cups_strncasecmp(option, "AP_FIRSTPAGE_", 13) && |
1015 | !_cups_strcasecmp(constptr->option->keyword, option + 13)) | |
e60ec91f MS |
1016 | break; |
1017 | } | |
1018 | ||
e07d4801 MS |
1019 | if (!i) |
1020 | continue; | |
1021 | } | |
e78998df | 1022 | |
e07d4801 | 1023 | DEBUG_puts("9ppd_test_constraints: Testing..."); |
06d4e77b | 1024 | |
d1c13e16 | 1025 | for (i = consts->num_constraints, constptr = consts->constraints; |
e78998df MS |
1026 | i > 0; |
1027 | i --, constptr ++) | |
1028 | { | |
e07d4801 | 1029 | DEBUG_printf(("9ppd_test_constraints: %s=%s?", constptr->option->keyword, |
06d4e77b MS |
1030 | constptr->choice ? constptr->choice->choice : "")); |
1031 | ||
e78998df | 1032 | if (constptr->choice && |
88f9aafc MS |
1033 | (!_cups_strcasecmp(constptr->option->keyword, "PageSize") || |
1034 | !_cups_strcasecmp(constptr->option->keyword, "PageRegion"))) | |
e78998df MS |
1035 | { |
1036 | /* | |
1037 | * PageSize and PageRegion are used depending on the selected input slot | |
1038 | * and manual feed mode. Validate against the selected page size instead | |
1039 | * of an individual option... | |
1040 | */ | |
1041 | ||
06d4e77b | 1042 | if (option && choice && |
88f9aafc MS |
1043 | (!_cups_strcasecmp(option, "PageSize") || |
1044 | !_cups_strcasecmp(option, "PageRegion"))) | |
06d4e77b MS |
1045 | { |
1046 | value = choice; | |
06d4e77b MS |
1047 | } |
1048 | else if ((value = cupsGetOption("PageSize", num_options, | |
1049 | options)) == NULL) | |
e78998df MS |
1050 | if ((value = cupsGetOption("PageRegion", num_options, |
1051 | options)) == NULL) | |
1052 | if ((value = cupsGetOption("media", num_options, options)) == NULL) | |
1053 | { | |
1054 | ppd_size_t *size = ppdPageSize(ppd, NULL); | |
1055 | ||
1056 | if (size) | |
1057 | value = size->name; | |
1058 | } | |
1059 | ||
88f9aafc | 1060 | if (value && !_cups_strncasecmp(value, "Custom.", 7)) |
d1c13e16 MS |
1061 | value = "Custom"; |
1062 | ||
e60ec91f | 1063 | if (option && choice && |
88f9aafc MS |
1064 | (!_cups_strcasecmp(option, "AP_FIRSTPAGE_PageSize") || |
1065 | !_cups_strcasecmp(option, "AP_FIRSTPAGE_PageRegion"))) | |
e60ec91f MS |
1066 | { |
1067 | firstvalue = choice; | |
1068 | } | |
1069 | else if ((firstvalue = cupsGetOption("AP_FIRSTPAGE_PageSize", | |
1070 | num_options, options)) == NULL) | |
1071 | firstvalue = cupsGetOption("AP_FIRSTPAGE_PageRegion", num_options, | |
1072 | options); | |
1073 | ||
88f9aafc | 1074 | if (firstvalue && !_cups_strncasecmp(firstvalue, "Custom.", 7)) |
e60ec91f MS |
1075 | firstvalue = "Custom"; |
1076 | ||
88f9aafc MS |
1077 | if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) && |
1078 | (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice))) | |
06d4e77b | 1079 | { |
e07d4801 | 1080 | DEBUG_puts("9ppd_test_constraints: NO"); |
e78998df | 1081 | break; |
06d4e77b | 1082 | } |
e78998df MS |
1083 | } |
1084 | else if (constptr->choice) | |
1085 | { | |
e60ec91f MS |
1086 | /* |
1087 | * Compare against the constrained choice... | |
1088 | */ | |
1089 | ||
88f9aafc | 1090 | if (option && choice && !_cups_strcasecmp(option, constptr->option->keyword)) |
06d4e77b | 1091 | { |
88f9aafc | 1092 | if (!_cups_strncasecmp(choice, "Custom.", 7)) |
d1c13e16 MS |
1093 | value = "Custom"; |
1094 | else | |
1095 | value = choice; | |
06d4e77b MS |
1096 | } |
1097 | else if ((value = cupsGetOption(constptr->option->keyword, num_options, | |
1098 | options)) != NULL) | |
e78998df | 1099 | { |
88f9aafc | 1100 | if (!_cups_strncasecmp(value, "Custom.", 7)) |
d1c13e16 | 1101 | value = "Custom"; |
e60ec91f MS |
1102 | } |
1103 | else if (constptr->choice->marked) | |
1104 | value = constptr->choice->choice; | |
1105 | else | |
1106 | value = NULL; | |
d1c13e16 | 1107 | |
e60ec91f MS |
1108 | /* |
1109 | * Now check AP_FIRSTPAGE_option... | |
1110 | */ | |
1111 | ||
1112 | snprintf(firstpage, sizeof(firstpage), "AP_FIRSTPAGE_%s", | |
1113 | constptr->option->keyword); | |
1114 | ||
88f9aafc | 1115 | if (option && choice && !_cups_strcasecmp(option, firstpage)) |
e60ec91f | 1116 | { |
88f9aafc | 1117 | if (!_cups_strncasecmp(choice, "Custom.", 7)) |
e60ec91f MS |
1118 | firstvalue = "Custom"; |
1119 | else | |
1120 | firstvalue = choice; | |
1121 | } | |
1122 | else if ((firstvalue = cupsGetOption(firstpage, num_options, | |
1123 | options)) != NULL) | |
1124 | { | |
88f9aafc | 1125 | if (!_cups_strncasecmp(firstvalue, "Custom.", 7)) |
e60ec91f | 1126 | firstvalue = "Custom"; |
e78998df | 1127 | } |
e60ec91f MS |
1128 | else |
1129 | firstvalue = NULL; | |
1130 | ||
1131 | DEBUG_printf(("9ppd_test_constraints: value=%s, firstvalue=%s", value, | |
1132 | firstvalue)); | |
1133 | ||
88f9aafc MS |
1134 | if ((!value || _cups_strcasecmp(value, constptr->choice->choice)) && |
1135 | (!firstvalue || _cups_strcasecmp(firstvalue, constptr->choice->choice))) | |
06d4e77b | 1136 | { |
e07d4801 | 1137 | DEBUG_puts("9ppd_test_constraints: NO"); |
06d4e77b MS |
1138 | break; |
1139 | } | |
1140 | } | |
1141 | else if (option && choice && | |
88f9aafc | 1142 | !_cups_strcasecmp(option, constptr->option->keyword)) |
06d4e77b | 1143 | { |
88f9aafc MS |
1144 | if (!_cups_strcasecmp(choice, "None") || !_cups_strcasecmp(choice, "Off") || |
1145 | !_cups_strcasecmp(choice, "False")) | |
d1c13e16 | 1146 | { |
e07d4801 | 1147 | DEBUG_puts("9ppd_test_constraints: NO"); |
e60ec91f | 1148 | break; |
d1c13e16 | 1149 | } |
e78998df MS |
1150 | } |
1151 | else if ((value = cupsGetOption(constptr->option->keyword, num_options, | |
e60ec91f | 1152 | options)) != NULL) |
e78998df | 1153 | { |
88f9aafc MS |
1154 | if (!_cups_strcasecmp(value, "None") || !_cups_strcasecmp(value, "Off") || |
1155 | !_cups_strcasecmp(value, "False")) | |
06d4e77b | 1156 | { |
e07d4801 | 1157 | DEBUG_puts("9ppd_test_constraints: NO"); |
06d4e77b MS |
1158 | break; |
1159 | } | |
e78998df MS |
1160 | } |
1161 | else | |
1162 | { | |
e60ec91f | 1163 | key.option = constptr->option; |
e78998df MS |
1164 | |
1165 | if ((marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) | |
e60ec91f | 1166 | == NULL || |
88f9aafc MS |
1167 | (!_cups_strcasecmp(marked->choice, "None") || |
1168 | !_cups_strcasecmp(marked->choice, "Off") || | |
1169 | !_cups_strcasecmp(marked->choice, "False"))) | |
06d4e77b | 1170 | { |
e07d4801 | 1171 | DEBUG_puts("9ppd_test_constraints: NO"); |
e78998df | 1172 | break; |
06d4e77b | 1173 | } |
e78998df MS |
1174 | } |
1175 | } | |
1176 | ||
d1c13e16 | 1177 | if (i <= 0) |
e78998df MS |
1178 | { |
1179 | if (!active) | |
1180 | active = cupsArrayNew(NULL, NULL); | |
1181 | ||
1182 | cupsArrayAdd(active, consts); | |
e07d4801 | 1183 | DEBUG_puts("9ppd_test_constraints: Added..."); |
e78998df MS |
1184 | } |
1185 | } | |
1186 | ||
1187 | cupsArrayRestore(ppd->marked); | |
1188 | ||
e07d4801 | 1189 | DEBUG_printf(("8ppd_test_constraints: Found %d active constraints!", |
06d4e77b MS |
1190 | cupsArrayCount(active))); |
1191 | ||
e78998df MS |
1192 | return (active); |
1193 | } |