]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/mark.c
Merge changes from CUPS trunk, r6739.
[thirdparty/cups.git] / cups / mark.c
1 /*
2 * "$Id: mark.c 6703 2007-07-20 21:28:10Z mike $"
3 *
4 * Option marking routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
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 *
21 * ppdConflicts() - Check to see if there are any conflicts.
22 * ppdFindChoice() - Return a pointer to an option choice.
23 * ppdFindMarkedChoice() - Return the marked choice for the specified option.
24 * ppdFindOption() - Return a pointer to the specified option.
25 * ppdFirstOption() - Return the first option in the PPD file.
26 * ppdNextOption() - Return the next option in the PPD file.
27 * ppdIsMarked() - Check to see if an option is marked...
28 * ppdMarkDefaults() - Mark all default options in the PPD file.
29 * ppdMarkOption() - Mark an option in a PPD file.
30 * ppd_defaults() - Set the defaults for this group and all sub-groups.
31 */
32
33 /*
34 * Include necessary headers...
35 */
36
37 #include "cups.h"
38 #include "string.h"
39 #include "debug.h"
40
41
42 /*
43 * Local functions...
44 */
45
46 static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
47
48
49 /*
50 * 'ppdConflicts()' - Check to see if there are any conflicts.
51 */
52
53 int /* O - Number of conflicts found */
54 ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
55 {
56 int i, /* Looping variable */
57 conflicts; /* Number of conflicts */
58 ppd_const_t *c; /* Current constraint */
59 ppd_option_t *o1, *o2; /* Options */
60 ppd_choice_t *c1, *c2; /* Choices */
61 ppd_choice_t key; /* Search key */
62
63
64 if (!ppd)
65 return (0);
66
67 /*
68 * Clear all conflicts...
69 */
70
71 conflicts = 0;
72
73 for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd))
74 o1->conflicted = 0;
75
76 cupsArraySave(ppd->marked);
77
78 /*
79 * Loop through all of the UI constraints and flag any options
80 * that conflict...
81 */
82
83 for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
84 i > 0;
85 i --, c ++)
86 {
87 /*
88 * Grab pointers to the first option...
89 */
90
91 if (!o1 || strcmp(c->option1, o1->keyword))
92 {
93 o1 = ppdFindOption(ppd, c->option1);
94 c1 = NULL;
95 }
96
97 if (!o1)
98 continue;
99 else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
100 {
101 /*
102 * This constraint maps to a specific choice.
103 */
104
105 key.option = o1;
106
107 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
108 (!c1->marked || strcmp(c->choice1, c1->choice)))
109 c1 = NULL;
110 }
111 else if (!c1)
112 {
113 /*
114 * This constraint applies to any choice for this option.
115 */
116
117 key.option = o1;
118
119 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
120 (!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") ||
121 !strcasecmp(c1->choice, "False")))
122 c1 = NULL;
123 }
124
125 /*
126 * Grab pointers to the second option...
127 */
128
129 if (!o2 || strcmp(c->option2, o2->keyword))
130 {
131 o2 = ppdFindOption(ppd, c->option2);
132 c2 = NULL;
133 }
134
135 if (!o2)
136 continue;
137 else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
138 {
139 /*
140 * This constraint maps to a specific choice.
141 */
142
143 key.option = o2;
144
145 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
146 (!c2->marked || strcmp(c->choice2, c2->choice)))
147 c2 = NULL;
148 }
149 else if (!c2)
150 {
151 /*
152 * This constraint applies to any choice for this option.
153 */
154
155 key.option = o2;
156
157 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
158 (!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") ||
159 !strcasecmp(c2->choice, "False")))
160 c2 = NULL;
161 }
162
163 /*
164 * If both options are marked then there is a conflict...
165 */
166
167 if (c1 && c1->marked && c2 && c2->marked)
168 {
169 DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n",
170 o1->keyword, c1->choice, o2->keyword, c2->choice,
171 c->option1, c->choice1, c->option2, c->choice2));
172 conflicts ++;
173 o1->conflicted = 1;
174 o2->conflicted = 1;
175 }
176 }
177
178 cupsArrayRestore(ppd->marked);
179
180 /*
181 * Return the number of conflicts found...
182 */
183
184 return (conflicts);
185 }
186
187
188 /*
189 * 'ppdFindChoice()' - Return a pointer to an option choice.
190 */
191
192 ppd_choice_t * /* O - Choice pointer or NULL */
193 ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
194 const char *choice) /* I - Name of choice */
195 {
196 int i; /* Looping var */
197 ppd_choice_t *c; /* Current choice */
198
199
200 if (o == NULL || choice == NULL)
201 return (NULL);
202
203 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
204 if (strcasecmp(c->choice, choice) == 0)
205 return (c);
206
207 return (NULL);
208 }
209
210
211 /*
212 * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
213 */
214
215 ppd_choice_t * /* O - Pointer to choice or NULL */
216 ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
217 const char *option) /* I - Keyword/option name */
218 {
219 ppd_choice_t key; /* Search key for choice */
220
221
222 if ((key.option = ppdFindOption(ppd, option)) == NULL)
223 return (NULL);
224
225 return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
226 }
227
228
229 /*
230 * 'ppdFindOption()' - Return a pointer to the specified option.
231 */
232
233 ppd_option_t * /* O - Pointer to option or NULL */
234 ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
235 const char *option) /* I - Option/Keyword name */
236 {
237 /*
238 * Range check input...
239 */
240
241 if (!ppd || !option)
242 return (NULL);
243
244 if (ppd->options)
245 {
246 /*
247 * Search in the array...
248 */
249
250 ppd_option_t key; /* Option search key */
251
252
253 strlcpy(key.keyword, option, sizeof(key.keyword));
254
255 return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
256 }
257 else
258 {
259 /*
260 * Search in each group...
261 */
262
263 int i, j; /* Looping vars */
264 ppd_group_t *group; /* Current group */
265 ppd_option_t *optptr; /* Current option */
266
267
268 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
269 for (j = group->num_options, optptr = group->options;
270 j > 0;
271 j --, optptr ++)
272 if (!strcasecmp(optptr->keyword, option))
273 return (optptr);
274
275 return (NULL);
276 }
277 }
278
279
280 /*
281 * 'ppdIsMarked()' - Check to see if an option is marked...
282 */
283
284 int /* O - Non-zero if option is marked */
285 ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
286 const char *option, /* I - Option/Keyword name */
287 const char *choice) /* I - Choice name */
288 {
289 ppd_choice_t key, /* Search key */
290 *c; /* Choice pointer */
291
292
293 if (!ppd)
294 return (0);
295
296 if ((key.option = ppdFindOption(ppd, option)) == NULL)
297 return (0);
298
299 if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
300 return (0);
301
302 return (!strcmp(c->choice, choice));
303 }
304
305
306 /*
307 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
308 */
309
310 void
311 ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
312 {
313 int i; /* Looping variables */
314 ppd_group_t *g; /* Current group */
315 ppd_choice_t *c; /* Current choice */
316
317
318 if (!ppd)
319 return;
320
321 /*
322 * Clean out the marked array...
323 */
324
325 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
326 c;
327 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
328 cupsArrayRemove(ppd->marked, c);
329
330 /*
331 * Then repopulate it with the defaults...
332 */
333
334 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
335 ppd_defaults(ppd, g);
336 }
337
338
339 /*
340 * 'ppdMarkOption()' - Mark an option in a PPD file.
341 *
342 * Notes:
343 *
344 * -1 is returned if the given option would conflict with any currently
345 * selected option.
346 */
347
348 int /* O - Number of conflicts */
349 ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
350 const char *option, /* I - Keyword */
351 const char *choice) /* I - Option name */
352 {
353 int i, j; /* Looping vars */
354 ppd_option_t *o; /* Option pointer */
355 ppd_choice_t *c, /* Choice pointer */
356 *oldc, /* Old choice pointer */
357 key; /* Search key for choice */
358 struct lconv *loc; /* Locale data */
359
360
361 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
362 ppd, option, choice));
363
364 /*
365 * Range check input...
366 */
367
368 if (!ppd || !option || !choice)
369 return (0);
370
371 /*
372 * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
373 * it clears the regular InputSlot choices...
374 */
375
376 if (!strcasecmp(option, "AP_D_InputSlot"))
377 {
378 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
379 {
380 key.option = o;
381 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
382 {
383 oldc->marked = 0;
384 cupsArrayRemove(ppd->marked, oldc);
385 }
386 }
387 }
388
389 /*
390 * Check for custom options...
391 */
392
393 if ((o = ppdFindOption(ppd, option)) == NULL)
394 return (0);
395
396 loc = localeconv();
397
398 if (!strncasecmp(choice, "Custom.", 7))
399 {
400 /*
401 * Handle a custom option...
402 */
403
404 if ((c = ppdFindChoice(o, "Custom")) == NULL)
405 return (0);
406
407 if (!strcasecmp(option, "PageSize"))
408 {
409 /*
410 * Handle custom page sizes...
411 */
412
413 ppdPageSize(ppd, choice);
414 }
415 else
416 {
417 /*
418 * Handle other custom options...
419 */
420
421 ppd_coption_t *coption; /* Custom option */
422 ppd_cparam_t *cparam; /* Custom parameter */
423 char *units; /* Custom points units */
424
425
426 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
427 {
428 if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
429 return (0);
430
431 switch (cparam->type)
432 {
433 case PPD_CUSTOM_CURVE :
434 case PPD_CUSTOM_INVCURVE :
435 case PPD_CUSTOM_REAL :
436 cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
437 NULL, loc);
438 break;
439
440 case PPD_CUSTOM_POINTS :
441 cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
442 &units,
443 loc);
444
445 if (units)
446 {
447 if (!strcasecmp(units, "cm"))
448 cparam->current.custom_points *= 72.0f / 2.54f;
449 else if (!strcasecmp(units, "mm"))
450 cparam->current.custom_points *= 72.0f / 25.4f;
451 else if (!strcasecmp(units, "m"))
452 cparam->current.custom_points *= 72.0f / 0.0254f;
453 else if (!strcasecmp(units, "in"))
454 cparam->current.custom_points *= 72.0f;
455 else if (!strcasecmp(units, "ft"))
456 cparam->current.custom_points *= 12.0f * 72.0f;
457 }
458 break;
459
460 case PPD_CUSTOM_INT :
461 cparam->current.custom_int = atoi(choice + 7);
462 break;
463
464 case PPD_CUSTOM_PASSCODE :
465 case PPD_CUSTOM_PASSWORD :
466 case PPD_CUSTOM_STRING :
467 if (cparam->current.custom_string)
468 free(cparam->current.custom_string);
469
470 cparam->current.custom_string = strdup(choice + 7);
471 break;
472 }
473 }
474 }
475
476 /*
477 * Make sure that we keep the option marked below...
478 */
479
480 choice = "Custom";
481 }
482 else if (choice[0] == '{')
483 {
484 /*
485 * Handle multi-value custom options...
486 */
487
488 ppd_coption_t *coption; /* Custom option */
489 ppd_cparam_t *cparam; /* Custom parameter */
490 char *units; /* Custom points units */
491 int num_vals; /* Number of values */
492 cups_option_t *vals, /* Values */
493 *val; /* Value */
494
495
496 if ((c = ppdFindChoice(o, "Custom")) == NULL)
497 return (0);
498
499 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
500 {
501 num_vals = cupsParseOptions(choice + 1, 0, &vals);
502
503 for (i = 0, val = vals; i < num_vals; i ++, val ++)
504 {
505 if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
506 continue;
507
508 switch (cparam->type)
509 {
510 case PPD_CUSTOM_CURVE :
511 case PPD_CUSTOM_INVCURVE :
512 case PPD_CUSTOM_REAL :
513 cparam->current.custom_real = (float)_cupsStrScand(val->value,
514 NULL, loc);
515 break;
516
517 case PPD_CUSTOM_POINTS :
518 cparam->current.custom_points = (float)_cupsStrScand(val->value,
519 &units,
520 loc);
521
522 if (units)
523 {
524 if (!strcasecmp(units, "cm"))
525 cparam->current.custom_points *= 72.0f / 2.54f;
526 else if (!strcasecmp(units, "mm"))
527 cparam->current.custom_points *= 72.0f / 25.4f;
528 else if (!strcasecmp(units, "m"))
529 cparam->current.custom_points *= 72.0f / 0.0254f;
530 else if (!strcasecmp(units, "in"))
531 cparam->current.custom_points *= 72.0f;
532 else if (!strcasecmp(units, "ft"))
533 cparam->current.custom_points *= 12.0f * 72.0f;
534 }
535 break;
536
537 case PPD_CUSTOM_INT :
538 cparam->current.custom_int = atoi(val->value);
539 break;
540
541 case PPD_CUSTOM_PASSCODE :
542 case PPD_CUSTOM_PASSWORD :
543 case PPD_CUSTOM_STRING :
544 if (cparam->current.custom_string)
545 free(cparam->current.custom_string);
546
547 cparam->current.custom_string = strdup(val->value);
548 break;
549 }
550 }
551
552 cupsFreeOptions(num_vals, vals);
553 }
554 }
555 else
556 {
557 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
558 if (!strcasecmp(c->choice, choice))
559 break;
560
561 if (!i)
562 return (0);
563 }
564
565 /*
566 * Option found; mark it and then handle unmarking any other options.
567 */
568
569 if (o->ui != PPD_UI_PICKMANY)
570 {
571 /*
572 * Unmark all other choices...
573 */
574
575 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
576 {
577 oldc->marked = 0;
578 cupsArrayRemove(ppd->marked, oldc);
579 }
580
581 if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
582 {
583 /*
584 * Mark current page size...
585 */
586
587 for (j = 0; j < ppd->num_sizes; j ++)
588 ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
589 choice);
590
591 /*
592 * Unmark the current PageSize or PageRegion setting, as
593 * appropriate...
594 */
595
596 if (!strcasecmp(option, "PageSize"))
597 {
598 if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
599 {
600 key.option = o;
601 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
602 {
603 oldc->marked = 0;
604 cupsArrayRemove(ppd->marked, oldc);
605 }
606 }
607 }
608 else
609 {
610 if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
611 {
612 key.option = o;
613 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
614 {
615 oldc->marked = 0;
616 cupsArrayRemove(ppd->marked, oldc);
617 }
618 }
619 }
620 }
621 else if (!strcasecmp(option, "InputSlot"))
622 {
623 /*
624 * Unmark ManualFeed option...
625 */
626
627 if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
628 {
629 key.option = o;
630 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
631 {
632 oldc->marked = 0;
633 cupsArrayRemove(ppd->marked, oldc);
634 }
635 }
636 }
637 else if (!strcasecmp(option, "ManualFeed") &&
638 !strcasecmp(choice, "True"))
639 {
640 /*
641 * Unmark InputSlot option...
642 */
643
644 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
645 {
646 key.option = o;
647 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
648 {
649 oldc->marked = 0;
650 cupsArrayRemove(ppd->marked, oldc);
651 }
652 }
653 }
654 }
655
656 c->marked = 1;
657
658 cupsArrayAdd(ppd->marked, c);
659
660 /*
661 * Return the number of conflicts...
662 */
663
664 return (ppdConflicts(ppd));
665 }
666
667
668 /*
669 * 'ppdFirstOption()' - Return the first option in the PPD file.
670 *
671 * Options are returned from all groups in sorted order.
672 *
673 * @since CUPS 1.2@
674 */
675
676 ppd_option_t * /* O - First option or NULL */
677 ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
678 {
679 if (!ppd)
680 return (NULL);
681 else
682 return ((ppd_option_t *)cupsArrayFirst(ppd->options));
683 }
684
685
686 /*
687 * 'ppdNextOption()' - Return the next option in the PPD file.
688 *
689 * Options are returned from all groups in sorted order.
690 *
691 * @since CUPS 1.2@
692 */
693
694 ppd_option_t * /* O - Next option or NULL */
695 ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
696 {
697 if (!ppd)
698 return (NULL);
699 else
700 return ((ppd_option_t *)cupsArrayNext(ppd->options));
701 }
702
703
704 /*
705 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
706 */
707
708 static void
709 ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
710 ppd_group_t *g) /* I - Group to default */
711 {
712 int i; /* Looping var */
713 ppd_option_t *o; /* Current option */
714 ppd_group_t *sg; /* Current sub-group */
715
716
717 for (i = g->num_options, o = g->options; i > 0; i --, o ++)
718 if (strcasecmp(o->keyword, "PageRegion") != 0)
719 ppdMarkOption(ppd, o->keyword, o->defchoice);
720
721 for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
722 ppd_defaults(ppd, sg);
723 }
724
725
726 /*
727 * End of "$Id: mark.c 6703 2007-07-20 21:28:10Z mike $".
728 */