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