]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/mark.c
Merge changes from CUPS 1.4svn-r7696.
[thirdparty/cups.git] / cups / mark.c
1 /*
2 * "$Id: mark.c 7605 2008-05-21 00:36:25Z mike $"
3 *
4 * Option marking routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 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 * cupsMarkOptions() - Mark command-line options in a PPD file.
22 * ppdConflicts() - Check to see if there are any conflicts among the
23 * marked option choices.
24 * ppdFindChoice() - Return a pointer to an option choice.
25 * ppdFindMarkedChoice() - Return the marked choice for the specified option.
26 * ppdFindOption() - Return a pointer to the specified option.
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 * ppdFirstOption() - Return the first option in the PPD file.
31 * ppdNextOption() - Return the next option in the PPD file.
32 * debug_marked() - Output the marked array to stdout...
33 * ppd_defaults() - Set the defaults for this group and all sub-groups.
34 * ppd_mark_choices() - Mark one or more option choices from a string.
35 */
36
37 /*
38 * Include necessary headers...
39 */
40
41 #include "cups.h"
42 #include "string.h"
43 #include "debug.h"
44
45
46 /*
47 * Local functions...
48 */
49
50 #ifdef DEBUG
51 static void debug_marked(ppd_file_t *ppd, const char *title);
52 #else
53 # define debug_marked(ppd,title)
54 #endif /* DEBUG */
55 static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
56 static int ppd_mark_choices(ppd_file_t *ppd, const char *options);
57
58
59 /*
60 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
61 *
62 * This function maps the IPP "finishings", "media", "mirror",
63 * "multiple-document-handling", "output-bin", "printer-resolution", and
64 * "sides" attributes to their corresponding PPD options and choices.
65 */
66
67 int /* O - 1 if conflicting */
68 cupsMarkOptions(
69 ppd_file_t *ppd, /* I - PPD file */
70 int num_options, /* I - Number of options */
71 cups_option_t *options) /* I - Options */
72 {
73 int i, j, k; /* Looping vars */
74 int conflict; /* Option conflicts */
75 char *val, /* Pointer into value */
76 *ptr, /* Pointer into string */
77 s[255]; /* Temporary string */
78 const char *page_size; /* PageSize option */
79 cups_option_t *optptr; /* Current option */
80 ppd_option_t *option; /* PPD option */
81 ppd_attr_t *attr; /* PPD attribute */
82 static const char * const duplex_options[] =
83 { /* Duplex option names */
84 "Duplex", /* Adobe */
85 "EFDuplex", /* EFI */
86 "EFDuplexing", /* EFI */
87 "KD03Duplex", /* Kodak */
88 "JCLDuplex" /* Samsung */
89 };
90 static const char * const duplex_one[] =
91 { /* one-sided names */
92 "None",
93 "False"
94 };
95 static const char * const duplex_two_long[] =
96 { /* two-sided-long-edge names */
97 "DuplexNoTumble", /* Adobe */
98 "LongEdge", /* EFI */
99 "Top" /* EFI */
100 };
101 static const char * const duplex_two_short[] =
102 { /* two-sided-long-edge names */
103 "DuplexTumble", /* Adobe */
104 "ShortEdge", /* EFI */
105 "Bottom" /* EFI */
106 };
107
108
109 /*
110 * Check arguments...
111 */
112
113 if (!ppd || num_options <= 0 || !options)
114 return (0);
115
116 debug_marked(ppd, "Before...");
117
118 /*
119 * Mark options...
120 */
121
122 conflict = 0;
123
124 for (i = num_options, optptr = options; i > 0; i --, optptr ++)
125 if (!strcasecmp(optptr->name, "media"))
126 {
127 /*
128 * Loop through the option string, separating it at commas and
129 * marking each individual option as long as the corresponding
130 * PPD option (PageSize, InputSlot, etc.) is not also set.
131 *
132 * For PageSize, we also check for an empty option value since
133 * some versions of MacOS X use it to specify auto-selection
134 * of the media based solely on the size.
135 */
136
137 page_size = cupsGetOption("PageSize", num_options, options);
138
139 for (val = optptr->value; *val;)
140 {
141 /*
142 * Extract the sub-option from the string...
143 */
144
145 for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
146 *ptr++ = *val++;
147 *ptr++ = '\0';
148
149 if (*val == ',')
150 val ++;
151
152 /*
153 * Mark it...
154 */
155
156 if (!page_size || !page_size[0])
157 if (ppdMarkOption(ppd, "PageSize", s))
158 conflict = 1;
159
160 if (cupsGetOption("InputSlot", num_options, options) == NULL)
161 if (ppdMarkOption(ppd, "InputSlot", s))
162 conflict = 1;
163
164 if (cupsGetOption("MediaType", num_options, options) == NULL)
165 if (ppdMarkOption(ppd, "MediaType", s))
166 conflict = 1;
167
168 if (cupsGetOption("EFMediaType", num_options, options) == NULL)
169 if (ppdMarkOption(ppd, "EFMediaType", s)) /* EFI */
170 conflict = 1;
171
172 if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
173 if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
174 conflict = 1;
175
176 if (strcasecmp(s, "manual") == 0 &&
177 cupsGetOption("ManualFeed", num_options, options) == NULL)
178 if (ppdMarkOption(ppd, "ManualFeed", "True"))
179 conflict = 1;
180 }
181 }
182 else if (!strcasecmp(optptr->name, "sides"))
183 {
184 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
185 if (cupsGetOption(duplex_options[j], num_options, options) != NULL)
186 break;
187
188 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
189 {
190 /*
191 * Don't override the PPD option with the IPP attribute...
192 */
193
194 continue;
195 }
196
197 if (!strcasecmp(optptr->value, "one-sided"))
198 {
199 /*
200 * Mark the appropriate duplex option for one-sided output...
201 */
202
203 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
204 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
205 break;
206
207 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
208 {
209 for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++)
210 if (ppdFindChoice(option, duplex_one[k]))
211 {
212 if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k]))
213 conflict = 1;
214
215 break;
216 }
217 }
218 }
219 else if (!strcasecmp(optptr->value, "two-sided-long-edge"))
220 {
221 /*
222 * Mark the appropriate duplex option for two-sided-long-edge output...
223 */
224
225 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
226 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
227 break;
228
229 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
230 {
231 for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++)
232 if (ppdFindChoice(option, duplex_two_long[k]))
233 {
234 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k]))
235 conflict = 1;
236
237 break;
238 }
239 }
240 }
241 else if (!strcasecmp(optptr->value, "two-sided-short-edge"))
242 {
243 /*
244 * Mark the appropriate duplex option for two-sided-short-edge output...
245 */
246
247 for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
248 if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
249 break;
250
251 if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
252 {
253 for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++)
254 if (ppdFindChoice(option, duplex_two_short[k]))
255 {
256 if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k]))
257 conflict = 1;
258
259 break;
260 }
261 }
262 }
263 }
264 else if (!strcasecmp(optptr->name, "resolution") ||
265 !strcasecmp(optptr->name, "printer-resolution"))
266 {
267 if (ppdMarkOption(ppd, "Resolution", optptr->value))
268 conflict = 1;
269 if (ppdMarkOption(ppd, "SetResolution", optptr->value))
270 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
271 conflict = 1;
272 if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */
273 conflict = 1;
274 if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */
275 conflict = 1;
276 }
277 else if (!strcasecmp(optptr->name, "output-bin"))
278 {
279 if (!cupsGetOption("OutputBin", num_options, options))
280 if (ppdMarkOption(ppd, "OutputBin", optptr->value))
281 conflict = 1;
282 }
283 else if (!strcasecmp(optptr->name, "multiple-document-handling"))
284 {
285 if (!cupsGetOption("Collate", num_options, options) &&
286 ppdFindOption(ppd, "Collate"))
287 {
288 if (strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
289 {
290 if (ppdMarkOption(ppd, "Collate", "True"))
291 conflict = 1;
292 }
293 else
294 {
295 if (ppdMarkOption(ppd, "Collate", "False"))
296 conflict = 1;
297 }
298 }
299 }
300 else if (!strcasecmp(optptr->name, "finishings"))
301 {
302 /*
303 * Lookup cupsIPPFinishings attributes for each value...
304 */
305
306 for (ptr = optptr->value; *ptr;)
307 {
308 /*
309 * Get the next finishings number...
310 */
311
312 if (!isdigit(*ptr & 255))
313 break;
314
315 if ((j = strtol(ptr, &ptr, 10)) < 3)
316 break;
317
318 /*
319 * Skip separator as needed...
320 */
321
322 if (*ptr == ',')
323 ptr ++;
324
325 /*
326 * Look it up in the PPD file...
327 */
328
329 sprintf(s, "%d", j);
330
331 if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL)
332 continue;
333
334 /*
335 * Apply "*Option Choice" settings from the attribute value...
336 */
337
338 if (ppd_mark_choices(ppd, attr->value))
339 conflict = 1;
340 }
341 }
342 else if (!strcasecmp(optptr->name, "mirror"))
343 {
344 if (ppdMarkOption(ppd, "MirrorPrint", optptr->value))
345 conflict = 1;
346 }
347 else if (ppdMarkOption(ppd, optptr->name, optptr->value))
348 conflict = 1;
349
350 debug_marked(ppd, "After...");
351
352 return (conflict);
353 }
354
355
356 /*
357 * 'ppdConflicts()' - Check to see if there are any conflicts among the
358 * marked option choices.
359 *
360 * The returned value is the same as returned by @link ppdMarkOption@.
361 */
362
363 int /* O - Number of conflicts found */
364 ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
365 {
366 int i, /* Looping variable */
367 conflicts; /* Number of conflicts */
368 ppd_const_t *c; /* Current constraint */
369 ppd_option_t *o1, *o2; /* Options */
370 ppd_choice_t *c1, *c2; /* Choices */
371 ppd_choice_t key; /* Search key */
372
373
374 if (!ppd)
375 return (0);
376
377 /*
378 * Clear all conflicts...
379 */
380
381 conflicts = 0;
382
383 for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd))
384 o1->conflicted = 0;
385
386 cupsArraySave(ppd->marked);
387
388 /*
389 * Loop through all of the UI constraints and flag any options
390 * that conflict...
391 */
392
393 for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
394 i > 0;
395 i --, c ++)
396 {
397 /*
398 * Grab pointers to the first option...
399 */
400
401 if (!o1 || strcmp(c->option1, o1->keyword))
402 {
403 o1 = ppdFindOption(ppd, c->option1);
404 c1 = NULL;
405 }
406
407 if (!o1)
408 continue;
409 else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
410 {
411 /*
412 * This constraint maps to a specific choice.
413 */
414
415 key.option = o1;
416
417 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
418 (!c1->marked || strcmp(c->choice1, c1->choice)))
419 c1 = NULL;
420 }
421 else if (!c1)
422 {
423 /*
424 * This constraint applies to any choice for this option.
425 */
426
427 key.option = o1;
428
429 if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
430 (!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") ||
431 !strcasecmp(c1->choice, "False")))
432 c1 = NULL;
433 }
434
435 /*
436 * Grab pointers to the second option...
437 */
438
439 if (!o2 || strcmp(c->option2, o2->keyword))
440 {
441 o2 = ppdFindOption(ppd, c->option2);
442 c2 = NULL;
443 }
444
445 if (!o2)
446 continue;
447 else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
448 {
449 /*
450 * This constraint maps to a specific choice.
451 */
452
453 key.option = o2;
454
455 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
456 (!c2->marked || strcmp(c->choice2, c2->choice)))
457 c2 = NULL;
458 }
459 else if (!c2)
460 {
461 /*
462 * This constraint applies to any choice for this option.
463 */
464
465 key.option = o2;
466
467 if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
468 (!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") ||
469 !strcasecmp(c2->choice, "False")))
470 c2 = NULL;
471 }
472
473 /*
474 * If both options are marked then there is a conflict...
475 */
476
477 if (c1 && c1->marked && c2 && c2->marked)
478 {
479 DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n",
480 o1->keyword, c1->choice, o2->keyword, c2->choice,
481 c->option1, c->choice1, c->option2, c->choice2));
482 conflicts ++;
483 o1->conflicted = 1;
484 o2->conflicted = 1;
485 }
486 }
487
488 cupsArrayRestore(ppd->marked);
489
490 /*
491 * Return the number of conflicts found...
492 */
493
494 return (conflicts);
495 }
496
497
498 /*
499 * 'ppdFindChoice()' - Return a pointer to an option choice.
500 */
501
502 ppd_choice_t * /* O - Choice pointer or @code NULL@ */
503 ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
504 const char *choice) /* I - Name of choice */
505 {
506 int i; /* Looping var */
507 ppd_choice_t *c; /* Current choice */
508
509
510 if (!o || !choice)
511 return (NULL);
512
513 if (choice[0] == '{' || !strncasecmp(choice, "Custom.", 7))
514 choice = "Custom";
515
516 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
517 if (!strcasecmp(c->choice, choice))
518 return (c);
519
520 return (NULL);
521 }
522
523
524 /*
525 * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
526 */
527
528 ppd_choice_t * /* O - Pointer to choice or @code NULL@ */
529 ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
530 const char *option) /* I - Keyword/option name */
531 {
532 ppd_choice_t key; /* Search key for choice */
533
534
535 if ((key.option = ppdFindOption(ppd, option)) == NULL)
536 return (NULL);
537
538 return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
539 }
540
541
542 /*
543 * 'ppdFindOption()' - Return a pointer to the specified option.
544 */
545
546 ppd_option_t * /* O - Pointer to option or @code NULL@ */
547 ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
548 const char *option) /* I - Option/Keyword name */
549 {
550 /*
551 * Range check input...
552 */
553
554 if (!ppd || !option)
555 return (NULL);
556
557 if (ppd->options)
558 {
559 /*
560 * Search in the array...
561 */
562
563 ppd_option_t key; /* Option search key */
564
565
566 strlcpy(key.keyword, option, sizeof(key.keyword));
567
568 return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
569 }
570 else
571 {
572 /*
573 * Search in each group...
574 */
575
576 int i, j; /* Looping vars */
577 ppd_group_t *group; /* Current group */
578 ppd_option_t *optptr; /* Current option */
579
580
581 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
582 for (j = group->num_options, optptr = group->options;
583 j > 0;
584 j --, optptr ++)
585 if (!strcasecmp(optptr->keyword, option))
586 return (optptr);
587
588 return (NULL);
589 }
590 }
591
592
593 /*
594 * 'ppdIsMarked()' - Check to see if an option is marked.
595 */
596
597 int /* O - Non-zero if option is marked */
598 ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
599 const char *option, /* I - Option/Keyword name */
600 const char *choice) /* I - Choice name */
601 {
602 ppd_choice_t key, /* Search key */
603 *c; /* Choice pointer */
604
605
606 if (!ppd)
607 return (0);
608
609 if ((key.option = ppdFindOption(ppd, option)) == NULL)
610 return (0);
611
612 if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
613 return (0);
614
615 return (!strcmp(c->choice, choice));
616 }
617
618
619 /*
620 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
621 */
622
623 void
624 ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
625 {
626 int i; /* Looping variables */
627 ppd_group_t *g; /* Current group */
628 ppd_choice_t *c; /* Current choice */
629
630
631 if (!ppd)
632 return;
633
634 /*
635 * Clean out the marked array...
636 */
637
638 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
639 c;
640 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
641 cupsArrayRemove(ppd->marked, c);
642
643 /*
644 * Then repopulate it with the defaults...
645 */
646
647 for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
648 ppd_defaults(ppd, g);
649 }
650
651
652 /*
653 * 'ppdMarkOption()' - Mark an option in a PPD file.
654 */
655
656 int /* O - Number of conflicts */
657 ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
658 const char *option, /* I - Keyword */
659 const char *choice) /* I - Option name */
660 {
661 int i, j; /* Looping vars */
662 ppd_option_t *o; /* Option pointer */
663 ppd_choice_t *c, /* Choice pointer */
664 *oldc, /* Old choice pointer */
665 key; /* Search key for choice */
666 struct lconv *loc; /* Locale data */
667
668
669 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
670 ppd, option, choice));
671
672 /*
673 * Range check input...
674 */
675
676 if (!ppd || !option || !choice)
677 return (0);
678
679 /*
680 * AP_D_InputSlot is the "default input slot" on MacOS X, and setting
681 * it clears the regular InputSlot choices...
682 */
683
684 if (!strcasecmp(option, "AP_D_InputSlot"))
685 {
686 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
687 {
688 key.option = o;
689 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
690 {
691 oldc->marked = 0;
692 cupsArrayRemove(ppd->marked, oldc);
693 }
694 }
695 }
696
697 /*
698 * Check for custom options...
699 */
700
701 if ((o = ppdFindOption(ppd, option)) == NULL)
702 return (0);
703
704 loc = localeconv();
705
706 if (!strncasecmp(choice, "Custom.", 7))
707 {
708 /*
709 * Handle a custom option...
710 */
711
712 if ((c = ppdFindChoice(o, "Custom")) == NULL)
713 return (0);
714
715 if (!strcasecmp(option, "PageSize"))
716 {
717 /*
718 * Handle custom page sizes...
719 */
720
721 ppdPageSize(ppd, choice);
722 }
723 else
724 {
725 /*
726 * Handle other custom options...
727 */
728
729 ppd_coption_t *coption; /* Custom option */
730 ppd_cparam_t *cparam; /* Custom parameter */
731 char *units; /* Custom points units */
732
733
734 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
735 {
736 if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
737 return (0);
738
739 switch (cparam->type)
740 {
741 case PPD_CUSTOM_CURVE :
742 case PPD_CUSTOM_INVCURVE :
743 case PPD_CUSTOM_REAL :
744 cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
745 NULL, loc);
746 break;
747
748 case PPD_CUSTOM_POINTS :
749 cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
750 &units,
751 loc);
752
753 if (units)
754 {
755 if (!strcasecmp(units, "cm"))
756 cparam->current.custom_points *= 72.0f / 2.54f;
757 else if (!strcasecmp(units, "mm"))
758 cparam->current.custom_points *= 72.0f / 25.4f;
759 else if (!strcasecmp(units, "m"))
760 cparam->current.custom_points *= 72.0f / 0.0254f;
761 else if (!strcasecmp(units, "in"))
762 cparam->current.custom_points *= 72.0f;
763 else if (!strcasecmp(units, "ft"))
764 cparam->current.custom_points *= 12.0f * 72.0f;
765 }
766 break;
767
768 case PPD_CUSTOM_INT :
769 cparam->current.custom_int = atoi(choice + 7);
770 break;
771
772 case PPD_CUSTOM_PASSCODE :
773 case PPD_CUSTOM_PASSWORD :
774 case PPD_CUSTOM_STRING :
775 if (cparam->current.custom_string)
776 _cupsStrFree(cparam->current.custom_string);
777
778 cparam->current.custom_string = _cupsStrAlloc(choice + 7);
779 break;
780 }
781 }
782 }
783
784 /*
785 * Make sure that we keep the option marked below...
786 */
787
788 choice = "Custom";
789 }
790 else if (choice[0] == '{')
791 {
792 /*
793 * Handle multi-value custom options...
794 */
795
796 ppd_coption_t *coption; /* Custom option */
797 ppd_cparam_t *cparam; /* Custom parameter */
798 char *units; /* Custom points units */
799 int num_vals; /* Number of values */
800 cups_option_t *vals, /* Values */
801 *val; /* Value */
802
803
804 if ((c = ppdFindChoice(o, "Custom")) == NULL)
805 return (0);
806
807 if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
808 {
809 num_vals = cupsParseOptions(choice + 1, 0, &vals);
810
811 for (i = 0, val = vals; i < num_vals; i ++, val ++)
812 {
813 if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
814 continue;
815
816 switch (cparam->type)
817 {
818 case PPD_CUSTOM_CURVE :
819 case PPD_CUSTOM_INVCURVE :
820 case PPD_CUSTOM_REAL :
821 cparam->current.custom_real = (float)_cupsStrScand(val->value,
822 NULL, loc);
823 break;
824
825 case PPD_CUSTOM_POINTS :
826 cparam->current.custom_points = (float)_cupsStrScand(val->value,
827 &units,
828 loc);
829
830 if (units)
831 {
832 if (!strcasecmp(units, "cm"))
833 cparam->current.custom_points *= 72.0f / 2.54f;
834 else if (!strcasecmp(units, "mm"))
835 cparam->current.custom_points *= 72.0f / 25.4f;
836 else if (!strcasecmp(units, "m"))
837 cparam->current.custom_points *= 72.0f / 0.0254f;
838 else if (!strcasecmp(units, "in"))
839 cparam->current.custom_points *= 72.0f;
840 else if (!strcasecmp(units, "ft"))
841 cparam->current.custom_points *= 12.0f * 72.0f;
842 }
843 break;
844
845 case PPD_CUSTOM_INT :
846 cparam->current.custom_int = atoi(val->value);
847 break;
848
849 case PPD_CUSTOM_PASSCODE :
850 case PPD_CUSTOM_PASSWORD :
851 case PPD_CUSTOM_STRING :
852 if (cparam->current.custom_string)
853 _cupsStrFree(cparam->current.custom_string);
854
855 cparam->current.custom_string = _cupsStrAlloc(val->value);
856 break;
857 }
858 }
859
860 cupsFreeOptions(num_vals, vals);
861 }
862 }
863 else
864 {
865 for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
866 if (!strcasecmp(c->choice, choice))
867 break;
868
869 if (!i)
870 return (0);
871 }
872
873 /*
874 * Option found; mark it and then handle unmarking any other options.
875 */
876
877 if (o->ui != PPD_UI_PICKMANY)
878 {
879 /*
880 * Unmark all other choices...
881 */
882
883 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
884 {
885 oldc->marked = 0;
886 cupsArrayRemove(ppd->marked, oldc);
887 }
888
889 if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
890 {
891 /*
892 * Mark current page size...
893 */
894
895 for (j = 0; j < ppd->num_sizes; j ++)
896 ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
897 choice);
898
899 /*
900 * Unmark the current PageSize or PageRegion setting, as
901 * appropriate...
902 */
903
904 if (!strcasecmp(option, "PageSize"))
905 {
906 if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
907 {
908 key.option = o;
909 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
910 {
911 oldc->marked = 0;
912 cupsArrayRemove(ppd->marked, oldc);
913 }
914 }
915 }
916 else
917 {
918 if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
919 {
920 key.option = o;
921 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
922 {
923 oldc->marked = 0;
924 cupsArrayRemove(ppd->marked, oldc);
925 }
926 }
927 }
928 }
929 else if (!strcasecmp(option, "InputSlot"))
930 {
931 /*
932 * Unmark ManualFeed option...
933 */
934
935 if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
936 {
937 key.option = o;
938 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
939 {
940 oldc->marked = 0;
941 cupsArrayRemove(ppd->marked, oldc);
942 }
943 }
944 }
945 else if (!strcasecmp(option, "ManualFeed") &&
946 !strcasecmp(choice, "True"))
947 {
948 /*
949 * Unmark InputSlot option...
950 */
951
952 if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
953 {
954 key.option = o;
955 if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
956 {
957 oldc->marked = 0;
958 cupsArrayRemove(ppd->marked, oldc);
959 }
960 }
961 }
962 }
963
964 c->marked = 1;
965
966 cupsArrayAdd(ppd->marked, c);
967
968 /*
969 * Return the number of conflicts...
970 */
971
972 return (ppdConflicts(ppd));
973 }
974
975
976 /*
977 * 'ppdFirstOption()' - Return the first option in the PPD file.
978 *
979 * Options are returned from all groups in ascending alphanumeric order.
980 *
981 * @since CUPS 1.2@
982 */
983
984 ppd_option_t * /* O - First option or @code NULL@ */
985 ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
986 {
987 if (!ppd)
988 return (NULL);
989 else
990 return ((ppd_option_t *)cupsArrayFirst(ppd->options));
991 }
992
993
994 /*
995 * 'ppdNextOption()' - Return the next option in the PPD file.
996 *
997 * Options are returned from all groups in ascending alphanumeric order.
998 *
999 * @since CUPS 1.2@
1000 */
1001
1002 ppd_option_t * /* O - Next option or @code NULL@ */
1003 ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
1004 {
1005 if (!ppd)
1006 return (NULL);
1007 else
1008 return ((ppd_option_t *)cupsArrayNext(ppd->options));
1009 }
1010
1011
1012 #ifdef DEBUG
1013 /*
1014 * 'debug_marked()' - Output the marked array to stdout...
1015 */
1016
1017 static void
1018 debug_marked(ppd_file_t *ppd, /* I - PPD file data */
1019 const char *title) /* I - Title for list */
1020 {
1021 ppd_choice_t *c; /* Current choice */
1022
1023
1024 DEBUG_printf(("cupsMarkOptions: %s\n", title));
1025
1026 for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
1027 c;
1028 c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
1029 DEBUG_printf(("cupsMarkOptions: %s=%s\n", c->option->keyword, c->choice));
1030 }
1031 #endif /* DEBUG */
1032
1033
1034 /*
1035 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
1036 */
1037
1038 static void
1039 ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
1040 ppd_group_t *g) /* I - Group to default */
1041 {
1042 int i; /* Looping var */
1043 ppd_option_t *o; /* Current option */
1044 ppd_group_t *sg; /* Current sub-group */
1045
1046
1047 for (i = g->num_options, o = g->options; i > 0; i --, o ++)
1048 if (strcasecmp(o->keyword, "PageRegion") != 0)
1049 ppdMarkOption(ppd, o->keyword, o->defchoice);
1050
1051 for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
1052 ppd_defaults(ppd, sg);
1053 }
1054
1055
1056 /*
1057 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
1058 */
1059
1060 static int /* O - 1 if there are conflicts, 0 otherwise */
1061 ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
1062 const char *options) /* I - "*Option Choice ..." string */
1063 {
1064 char option[PPD_MAX_NAME], /* Current option */
1065 choice[PPD_MAX_NAME], /* Current choice */
1066 *ptr; /* Pointer into option or choice */
1067 int conflict = 0; /* Do we have a conflict? */
1068
1069
1070 if (!options)
1071 return (0);
1072
1073 /*
1074 * Read all of the "*Option Choice" pairs from the string, marking PPD
1075 * options as we go...
1076 */
1077
1078 while (*options)
1079 {
1080 /*
1081 * Skip leading whitespace...
1082 */
1083
1084 while (isspace(*options & 255))
1085 options ++;
1086
1087 if (*options != '*')
1088 break;
1089
1090 /*
1091 * Get the option name...
1092 */
1093
1094 options ++;
1095 ptr = option;
1096 while (*options && !isspace(*options & 255) &&
1097 ptr < (option + sizeof(option) - 1))
1098 *ptr++ = *options++;
1099
1100 if (ptr == option)
1101 break;
1102
1103 *ptr = '\0';
1104
1105 /*
1106 * Get the choice...
1107 */
1108
1109 while (isspace(*options & 255))
1110 options ++;
1111
1112 if (!*options)
1113 break;
1114
1115 ptr = choice;
1116 while (*options && !isspace(*options & 255) &&
1117 ptr < (choice + sizeof(choice) - 1))
1118 *ptr++ = *options++;
1119
1120 *ptr = '\0';
1121
1122 /*
1123 * Mark the option...
1124 */
1125
1126 if (ppdMarkOption(ppd, option, choice))
1127 conflict = 1;
1128 }
1129
1130 /*
1131 * Return whether we had any conflicts...
1132 */
1133
1134 return (conflict);
1135 }
1136
1137
1138 /*
1139 * End of "$Id: mark.c 7605 2008-05-21 00:36:25Z mike $".
1140 */