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