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