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