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