2 * Option marking routines for CUPS.
4 * Copyright 2007-2017 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
10 * PostScript is a trademark of Adobe Systems, Inc.
14 * Include necessary headers...
17 #include "cups-private.h"
18 #include "ppd-private.h"
19 #include "debug-internal.h"
27 static void ppd_debug_marked(ppd_file_t
*ppd
, const char *title
);
29 # define ppd_debug_marked(ppd,title)
31 static void ppd_defaults(ppd_file_t
*ppd
, ppd_group_t
*g
);
32 static void ppd_mark_choices(ppd_file_t
*ppd
, const char *s
);
33 static void ppd_mark_option(ppd_file_t
*ppd
, const char *option
,
38 * 'cupsMarkOptions()' - Mark command-line options in a PPD file.
40 * This function maps the IPP "finishings", "media", "mirror",
41 * "multiple-document-handling", "output-bin", "print-color-mode",
42 * "print-quality", "printer-resolution", and "sides" attributes to their
43 * corresponding PPD options and choices.
46 int /* O - 1 if conflicts exist, 0 otherwise */
48 ppd_file_t
*ppd
, /* I - PPD file */
49 int num_options
, /* I - Number of options */
50 cups_option_t
*options
) /* I - Options */
52 int i
, j
; /* Looping vars */
53 char *ptr
, /* Pointer into string */
54 s
[255]; /* Temporary string */
55 const char *val
, /* Pointer into value */
56 *media
, /* media option */
57 *output_bin
, /* output-bin option */
58 *page_size
, /* PageSize option */
59 *ppd_keyword
, /* PPD keyword */
60 *print_color_mode
, /* print-color-mode option */
61 *print_quality
, /* print-quality option */
62 *sides
; /* sides option */
63 cups_option_t
*optptr
; /* Current option */
64 ppd_attr_t
*attr
; /* PPD attribute */
65 _ppd_cache_t
*cache
; /* PPD cache and mapping data */
72 if (!ppd
|| num_options
<= 0 || !options
)
75 ppd_debug_marked(ppd
, "Before...");
78 * Do special handling for finishings, media, output-bin, output-mode,
79 * print-color-mode, print-quality, and PageSize...
82 media
= cupsGetOption("media", num_options
, options
);
83 output_bin
= cupsGetOption("output-bin", num_options
, options
);
84 page_size
= cupsGetOption("PageSize", num_options
, options
);
85 print_quality
= cupsGetOption("print-quality", num_options
, options
);
86 sides
= cupsGetOption("sides", num_options
, options
);
88 if ((print_color_mode
= cupsGetOption("print-color-mode", num_options
,
90 print_color_mode
= cupsGetOption("output-mode", num_options
, options
);
92 if ((media
|| output_bin
|| print_color_mode
|| print_quality
|| sides
) &&
96 * Load PPD cache and mapping data as needed...
99 ppd
->cache
= _ppdCacheCreateWithPPD(ppd
);
107 * Loop through the option string, separating it at commas and marking each
108 * individual option as long as the corresponding PPD option (PageSize,
109 * InputSlot, etc.) is not also set.
111 * For PageSize, we also check for an empty option value since some versions
112 * of macOS use it to specify auto-selection of the media based solely on
116 for (val
= media
; *val
;)
119 * Extract the sub-option from the string...
122 for (ptr
= s
; *val
&& *val
!= ',' && (size_t)(ptr
- s
) < (sizeof(s
) - 1);)
133 if (!page_size
|| !page_size
[0])
135 if (!_cups_strncasecmp(s
, "Custom.", 7) || ppdPageSize(ppd
, s
))
136 ppd_mark_option(ppd
, "PageSize", s
);
137 else if ((ppd_keyword
= _ppdCacheGetPageSize(cache
, NULL
, s
, NULL
)) != NULL
)
138 ppd_mark_option(ppd
, "PageSize", ppd_keyword
);
141 if (cache
&& cache
->source_option
&&
142 !cupsGetOption(cache
->source_option
, num_options
, options
) &&
143 (ppd_keyword
= _ppdCacheGetInputSlot(cache
, NULL
, s
)) != NULL
)
144 ppd_mark_option(ppd
, cache
->source_option
, ppd_keyword
);
146 if (!cupsGetOption("MediaType", num_options
, options
) &&
147 (ppd_keyword
= _ppdCacheGetMediaType(cache
, NULL
, s
)) != NULL
)
148 ppd_mark_option(ppd
, "MediaType", ppd_keyword
);
154 if (!cupsGetOption("com.apple.print.DocumentTicket.PMSpoolFormat",
155 num_options
, options
) &&
156 !cupsGetOption("APPrinterPreset", num_options
, options
) &&
157 (print_color_mode
|| print_quality
))
160 * Map output-mode and print-quality to a preset...
163 _pwg_print_color_mode_t pwg_pcm
;/* print-color-mode index */
164 _pwg_print_quality_t pwg_pq
; /* print-quality index */
165 cups_option_t
*preset
;/* Current preset option */
167 if (print_color_mode
&& !strcmp(print_color_mode
, "monochrome"))
168 pwg_pcm
= _PWG_PRINT_COLOR_MODE_MONOCHROME
;
170 pwg_pcm
= _PWG_PRINT_COLOR_MODE_COLOR
;
174 pwg_pq
= (_pwg_print_quality_t
)(atoi(print_quality
) - IPP_QUALITY_DRAFT
);
175 if (pwg_pq
< _PWG_PRINT_QUALITY_DRAFT
)
176 pwg_pq
= _PWG_PRINT_QUALITY_DRAFT
;
177 else if (pwg_pq
> _PWG_PRINT_QUALITY_HIGH
)
178 pwg_pq
= _PWG_PRINT_QUALITY_HIGH
;
181 pwg_pq
= _PWG_PRINT_QUALITY_NORMAL
;
183 if (cache
->num_presets
[pwg_pcm
][pwg_pq
] == 0)
186 * Try to find a preset that works so that we maximize the chances of us
187 * getting a good print using IPP attributes.
190 if (cache
->num_presets
[pwg_pcm
][_PWG_PRINT_QUALITY_NORMAL
] > 0)
191 pwg_pq
= _PWG_PRINT_QUALITY_NORMAL
;
192 else if (cache
->num_presets
[_PWG_PRINT_COLOR_MODE_COLOR
][pwg_pq
] > 0)
193 pwg_pcm
= _PWG_PRINT_COLOR_MODE_COLOR
;
196 pwg_pq
= _PWG_PRINT_QUALITY_NORMAL
;
197 pwg_pcm
= _PWG_PRINT_COLOR_MODE_COLOR
;
201 if (cache
->num_presets
[pwg_pcm
][pwg_pq
] > 0)
204 * Copy the preset options as long as the corresponding names are not
205 * already defined in the IPP request...
208 for (i
= cache
->num_presets
[pwg_pcm
][pwg_pq
],
209 preset
= cache
->presets
[pwg_pcm
][pwg_pq
];
213 if (!cupsGetOption(preset
->name
, num_options
, options
))
214 ppd_mark_option(ppd
, preset
->name
, preset
->value
);
219 if (output_bin
&& !cupsGetOption("OutputBin", num_options
, options
) &&
220 (ppd_keyword
= _ppdCacheGetOutputBin(cache
, output_bin
)) != NULL
)
223 * Map output-bin to OutputBin...
226 ppd_mark_option(ppd
, "OutputBin", ppd_keyword
);
229 if (sides
&& cache
->sides_option
&&
230 !cupsGetOption(cache
->sides_option
, num_options
, options
))
233 * Map sides to duplex option...
236 if (!strcmp(sides
, "one-sided") && cache
->sides_1sided
)
237 ppd_mark_option(ppd
, cache
->sides_option
, cache
->sides_1sided
);
238 else if (!strcmp(sides
, "two-sided-long-edge") &&
239 cache
->sides_2sided_long
)
240 ppd_mark_option(ppd
, cache
->sides_option
, cache
->sides_2sided_long
);
241 else if (!strcmp(sides
, "two-sided-short-edge") &&
242 cache
->sides_2sided_short
)
243 ppd_mark_option(ppd
, cache
->sides_option
, cache
->sides_2sided_short
);
248 * Mark other options...
251 for (i
= num_options
, optptr
= options
; i
> 0; i
--, optptr
++)
253 if (!_cups_strcasecmp(optptr
->name
, "media") ||
254 !_cups_strcasecmp(optptr
->name
, "output-bin") ||
255 !_cups_strcasecmp(optptr
->name
, "output-mode") ||
256 !_cups_strcasecmp(optptr
->name
, "print-quality") ||
257 !_cups_strcasecmp(optptr
->name
, "sides"))
259 else if (!_cups_strcasecmp(optptr
->name
, "resolution") ||
260 !_cups_strcasecmp(optptr
->name
, "printer-resolution"))
262 ppd_mark_option(ppd
, "Resolution", optptr
->value
);
263 ppd_mark_option(ppd
, "SetResolution", optptr
->value
);
264 /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
265 ppd_mark_option(ppd
, "JCLResolution", optptr
->value
);
267 ppd_mark_option(ppd
, "CNRes_PGP", optptr
->value
);
270 else if (!_cups_strcasecmp(optptr
->name
, "multiple-document-handling"))
272 if (!cupsGetOption("Collate", num_options
, options
) &&
273 ppdFindOption(ppd
, "Collate"))
275 if (_cups_strcasecmp(optptr
->value
, "separate-documents-uncollated-copies"))
276 ppd_mark_option(ppd
, "Collate", "True");
278 ppd_mark_option(ppd
, "Collate", "False");
281 else if (!_cups_strcasecmp(optptr
->name
, "finishings"))
284 * Lookup cupsIPPFinishings attributes for each value...
287 for (ptr
= optptr
->value
; *ptr
;)
290 * Get the next finishings number...
293 if (!isdigit(*ptr
& 255))
296 if ((j
= (int)strtol(ptr
, &ptr
, 10)) < 3)
300 * Skip separator as needed...
307 * Look it up in the PPD file...
312 if ((attr
= ppdFindAttr(ppd
, "cupsIPPFinishings", s
)) == NULL
)
316 * Apply "*Option Choice" settings from the attribute value...
319 ppd_mark_choices(ppd
, attr
->value
);
322 else if (!_cups_strcasecmp(optptr
->name
, "APPrinterPreset"))
325 * Lookup APPrinterPreset value...
328 if ((attr
= ppdFindAttr(ppd
, "APPrinterPreset", optptr
->value
)) != NULL
)
331 * Apply "*Option Choice" settings from the attribute value...
334 ppd_mark_choices(ppd
, attr
->value
);
337 else if (!_cups_strcasecmp(optptr
->name
, "mirror"))
338 ppd_mark_option(ppd
, "MirrorPrint", optptr
->value
);
340 ppd_mark_option(ppd
, optptr
->name
, optptr
->value
);
345 int pq
= atoi(print_quality
); /* print-quaity value */
347 if (pq
== IPP_QUALITY_DRAFT
)
348 ppd_mark_option(ppd
, "cupsPrintQuality", "Draft");
349 else if (pq
== IPP_QUALITY_HIGH
)
350 ppd_mark_option(ppd
, "cupsPrintQuality", "High");
352 ppd_mark_option(ppd
, "cupsPrintQuality", "Normal");
355 ppd_debug_marked(ppd
, "After...");
357 return (ppdConflicts(ppd
) > 0);
362 * 'ppdFindChoice()' - Return a pointer to an option choice.
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 */
369 int i
; /* Looping var */
370 ppd_choice_t
*c
; /* Current choice */
376 if (choice
[0] == '{' || !_cups_strncasecmp(choice
, "Custom.", 7))
379 for (i
= o
->num_choices
, c
= o
->choices
; i
> 0; i
--, c
++)
380 if (!_cups_strcasecmp(c
->choice
, choice
))
388 * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
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 */
395 ppd_choice_t key
, /* Search key for choice */
396 *marked
; /* Marked choice */
399 DEBUG_printf(("2ppdFindMarkedChoice(ppd=%p, option=\"%s\")", ppd
, option
));
401 if ((key
.option
= ppdFindOption(ppd
, option
)) == NULL
)
403 DEBUG_puts("3ppdFindMarkedChoice: Option not found, returning NULL");
407 marked
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
);
409 DEBUG_printf(("3ppdFindMarkedChoice: Returning %p(%s)...", marked
,
410 marked
? marked
->choice
: "NULL"));
417 * 'ppdFindOption()' - Return a pointer to the specified option.
420 ppd_option_t
* /* O - Pointer to option or @code NULL@ */
421 ppdFindOption(ppd_file_t
*ppd
, /* I - PPD file data */
422 const char *option
) /* I - Option/Keyword name */
425 * Range check input...
434 * Search in the array...
437 ppd_option_t key
; /* Option search key */
440 strlcpy(key
.keyword
, option
, sizeof(key
.keyword
));
442 return ((ppd_option_t
*)cupsArrayFind(ppd
->options
, &key
));
447 * Search in each group...
450 int i
, j
; /* Looping vars */
451 ppd_group_t
*group
; /* Current group */
452 ppd_option_t
*optptr
; /* Current option */
455 for (i
= ppd
->num_groups
, group
= ppd
->groups
; i
> 0; i
--, group
++)
456 for (j
= group
->num_options
, optptr
= group
->options
;
459 if (!_cups_strcasecmp(optptr
->keyword
, option
))
468 * 'ppdIsMarked()' - Check to see if an option is marked.
471 int /* O - Non-zero if option is marked */
472 ppdIsMarked(ppd_file_t
*ppd
, /* I - PPD file data */
473 const char *option
, /* I - Option/Keyword name */
474 const char *choice
) /* I - Choice name */
476 ppd_choice_t key
, /* Search key */
477 *c
; /* Choice pointer */
483 if ((key
.option
= ppdFindOption(ppd
, option
)) == NULL
)
486 if ((c
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
)) == NULL
)
489 return (!strcmp(c
->choice
, choice
));
494 * 'ppdMarkDefaults()' - Mark all default options in the PPD file.
498 ppdMarkDefaults(ppd_file_t
*ppd
) /* I - PPD file record */
500 int i
; /* Looping variables */
501 ppd_group_t
*g
; /* Current group */
502 ppd_choice_t
*c
; /* Current choice */
509 * Clean out the marked array...
512 for (c
= (ppd_choice_t
*)cupsArrayFirst(ppd
->marked
);
514 c
= (ppd_choice_t
*)cupsArrayNext(ppd
->marked
))
516 cupsArrayRemove(ppd
->marked
, c
);
521 * Then repopulate it with the defaults...
524 for (i
= ppd
->num_groups
, g
= ppd
->groups
; i
> 0; i
--, g
++)
525 ppd_defaults(ppd
, g
);
528 * Finally, tag any conflicts (API compatibility) once at the end.
536 * 'ppdMarkOption()' - Mark an option in a PPD file and return the number of
540 int /* O - Number of conflicts */
541 ppdMarkOption(ppd_file_t
*ppd
, /* I - PPD file record */
542 const char *option
, /* I - Keyword */
543 const char *choice
) /* I - Option name */
545 DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")",
546 ppd
, option
, choice
));
549 * Range check input...
552 if (!ppd
|| !option
|| !choice
)
559 ppd_mark_option(ppd
, option
, choice
);
562 * Return the number of conflicts...
565 return (ppdConflicts(ppd
));
570 * 'ppdFirstOption()' - Return the first option in the PPD file.
572 * Options are returned from all groups in ascending alphanumeric order.
574 * @since CUPS 1.2/macOS 10.5@
577 ppd_option_t
* /* O - First option or @code NULL@ */
578 ppdFirstOption(ppd_file_t
*ppd
) /* I - PPD file */
583 return ((ppd_option_t
*)cupsArrayFirst(ppd
->options
));
588 * 'ppdNextOption()' - Return the next option in the PPD file.
590 * Options are returned from all groups in ascending alphanumeric order.
592 * @since CUPS 1.2/macOS 10.5@
595 ppd_option_t
* /* O - Next option or @code NULL@ */
596 ppdNextOption(ppd_file_t
*ppd
) /* I - PPD file */
601 return ((ppd_option_t
*)cupsArrayNext(ppd
->options
));
606 * '_ppdParseOptions()' - Parse options from a PPD file.
608 * This function looks for strings of the form:
610 * *option choice ... *optionN choiceN
611 * property value ... propertyN valueN
613 * It stops when it finds a string that doesn't match this format.
616 int /* O - Number of options */
618 const char *s
, /* I - String to parse */
619 int num_options
, /* I - Number of options */
620 cups_option_t
**options
, /* IO - Options */
621 _ppd_parse_t which
) /* I - What to parse */
623 char option
[PPD_MAX_NAME
* 2 + 1], /* Current option/property */
624 choice
[PPD_MAX_NAME
], /* Current choice/value */
625 *ptr
; /* Pointer into option or choice */
629 return (num_options
);
632 * Read all of the "*Option Choice" and "property value" pairs from the
633 * string, add them to an options array as we go...
639 * Skip leading whitespace...
642 while (_cups_isspace(*s
))
646 * Get the option/property name...
650 while (*s
&& !_cups_isspace(*s
) && ptr
< (option
+ sizeof(option
) - 1))
653 if (ptr
== s
|| !_cups_isspace(*s
))
662 while (_cups_isspace(*s
))
669 while (*s
&& !_cups_isspace(*s
) && ptr
< (choice
+ sizeof(choice
) - 1))
672 if (*s
&& !_cups_isspace(*s
))
678 * Add it to the options array...
681 if (option
[0] == '*' && which
!= _PPD_PARSE_PROPERTIES
)
682 num_options
= cupsAddOption(option
+ 1, choice
, num_options
, options
);
683 else if (option
[0] != '*' && which
!= _PPD_PARSE_OPTIONS
)
684 num_options
= cupsAddOption(option
, choice
, num_options
, options
);
687 return (num_options
);
693 * 'ppd_debug_marked()' - Output the marked array to stdout...
697 ppd_debug_marked(ppd_file_t
*ppd
, /* I - PPD file data */
698 const char *title
) /* I - Title for list */
700 ppd_choice_t
*c
; /* Current choice */
703 DEBUG_printf(("2cupsMarkOptions: %s", title
));
705 for (c
= (ppd_choice_t
*)cupsArrayFirst(ppd
->marked
);
707 c
= (ppd_choice_t
*)cupsArrayNext(ppd
->marked
))
708 DEBUG_printf(("2cupsMarkOptions: %s=%s", c
->option
->keyword
, c
->choice
));
714 * 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
718 ppd_defaults(ppd_file_t
*ppd
, /* I - PPD file */
719 ppd_group_t
*g
) /* I - Group to default */
721 int i
; /* Looping var */
722 ppd_option_t
*o
; /* Current option */
723 ppd_group_t
*sg
; /* Current sub-group */
726 for (i
= g
->num_options
, o
= g
->options
; i
> 0; i
--, o
++)
727 if (_cups_strcasecmp(o
->keyword
, "PageRegion") != 0)
728 ppd_mark_option(ppd
, o
->keyword
, o
->defchoice
);
730 for (i
= g
->num_subgroups
, sg
= g
->subgroups
; i
> 0; i
--, sg
++)
731 ppd_defaults(ppd
, sg
);
736 * 'ppd_mark_choices()' - Mark one or more option choices from a string.
740 ppd_mark_choices(ppd_file_t
*ppd
, /* I - PPD file */
741 const char *s
) /* I - "*Option Choice ..." string */
743 int i
, /* Looping var */
744 num_options
; /* Number of options */
745 cups_option_t
*options
, /* Options */
746 *option
; /* Current option */
753 num_options
= _ppdParseOptions(s
, 0, &options
, 0);
755 for (i
= num_options
, option
= options
; i
> 0; i
--, option
++)
756 ppd_mark_option(ppd
, option
->name
, option
->value
);
758 cupsFreeOptions(num_options
, options
);
763 * 'ppd_mark_option()' - Quick mark an option without checking for conflicts.
767 ppd_mark_option(ppd_file_t
*ppd
, /* I - PPD file */
768 const char *option
, /* I - Option name */
769 const char *choice
) /* I - Choice name */
771 int i
, j
; /* Looping vars */
772 ppd_option_t
*o
; /* Option pointer */
773 ppd_choice_t
*c
, /* Choice pointer */
774 *oldc
, /* Old choice pointer */
775 key
; /* Search key for choice */
776 struct lconv
*loc
; /* Locale data */
779 DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")",
780 ppd
, option
, choice
));
783 * AP_D_InputSlot is the "default input slot" on macOS, and setting
784 * it clears the regular InputSlot choices...
787 if (!_cups_strcasecmp(option
, "AP_D_InputSlot"))
789 cupsArraySave(ppd
->options
);
791 if ((o
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
794 if ((oldc
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
)) != NULL
)
797 cupsArrayRemove(ppd
->marked
, oldc
);
801 cupsArrayRestore(ppd
->options
);
805 * Check for custom options...
808 cupsArraySave(ppd
->options
);
810 o
= ppdFindOption(ppd
, option
);
812 cupsArrayRestore(ppd
->options
);
819 if (!_cups_strncasecmp(choice
, "Custom.", 7))
822 * Handle a custom option...
825 if ((c
= ppdFindChoice(o
, "Custom")) == NULL
)
828 if (!_cups_strcasecmp(option
, "PageSize"))
831 * Handle custom page sizes...
834 ppdPageSize(ppd
, choice
);
839 * Handle other custom options...
842 ppd_coption_t
*coption
; /* Custom option */
843 ppd_cparam_t
*cparam
; /* Custom parameter */
844 char *units
; /* Custom points units */
847 if ((coption
= ppdFindCustomOption(ppd
, option
)) != NULL
)
849 if ((cparam
= (ppd_cparam_t
*)cupsArrayFirst(coption
->params
)) == NULL
)
852 switch (cparam
->type
)
854 case PPD_CUSTOM_CURVE
:
855 case PPD_CUSTOM_INVCURVE
:
856 case PPD_CUSTOM_REAL
:
857 cparam
->current
.custom_real
= (float)_cupsStrScand(choice
+ 7,
861 case PPD_CUSTOM_POINTS
:
862 cparam
->current
.custom_points
= (float)_cupsStrScand(choice
+ 7,
868 if (!_cups_strcasecmp(units
, "cm"))
869 cparam
->current
.custom_points
*= 72.0f
/ 2.54f
;
870 else if (!_cups_strcasecmp(units
, "mm"))
871 cparam
->current
.custom_points
*= 72.0f
/ 25.4f
;
872 else if (!_cups_strcasecmp(units
, "m"))
873 cparam
->current
.custom_points
*= 72.0f
/ 0.0254f
;
874 else if (!_cups_strcasecmp(units
, "in"))
875 cparam
->current
.custom_points
*= 72.0f
;
876 else if (!_cups_strcasecmp(units
, "ft"))
877 cparam
->current
.custom_points
*= 12.0f
* 72.0f
;
881 case PPD_CUSTOM_INT
:
882 cparam
->current
.custom_int
= atoi(choice
+ 7);
885 case PPD_CUSTOM_PASSCODE
:
886 case PPD_CUSTOM_PASSWORD
:
887 case PPD_CUSTOM_STRING
:
888 if (cparam
->current
.custom_string
)
889 _cupsStrFree(cparam
->current
.custom_string
);
891 cparam
->current
.custom_string
= _cupsStrAlloc(choice
+ 7);
898 * Make sure that we keep the option marked below...
903 else if (choice
[0] == '{')
906 * Handle multi-value custom options...
909 ppd_coption_t
*coption
; /* Custom option */
910 ppd_cparam_t
*cparam
; /* Custom parameter */
911 char *units
; /* Custom points units */
912 int num_vals
; /* Number of values */
913 cups_option_t
*vals
, /* Values */
917 if ((c
= ppdFindChoice(o
, "Custom")) == NULL
)
920 if ((coption
= ppdFindCustomOption(ppd
, option
)) != NULL
)
922 num_vals
= cupsParseOptions(choice
, 0, &vals
);
924 for (i
= 0, val
= vals
; i
< num_vals
; i
++, val
++)
926 if ((cparam
= ppdFindCustomParam(coption
, val
->name
)) == NULL
)
929 switch (cparam
->type
)
931 case PPD_CUSTOM_CURVE
:
932 case PPD_CUSTOM_INVCURVE
:
933 case PPD_CUSTOM_REAL
:
934 cparam
->current
.custom_real
= (float)_cupsStrScand(val
->value
,
938 case PPD_CUSTOM_POINTS
:
939 cparam
->current
.custom_points
= (float)_cupsStrScand(val
->value
,
945 if (!_cups_strcasecmp(units
, "cm"))
946 cparam
->current
.custom_points
*= 72.0f
/ 2.54f
;
947 else if (!_cups_strcasecmp(units
, "mm"))
948 cparam
->current
.custom_points
*= 72.0f
/ 25.4f
;
949 else if (!_cups_strcasecmp(units
, "m"))
950 cparam
->current
.custom_points
*= 72.0f
/ 0.0254f
;
951 else if (!_cups_strcasecmp(units
, "in"))
952 cparam
->current
.custom_points
*= 72.0f
;
953 else if (!_cups_strcasecmp(units
, "ft"))
954 cparam
->current
.custom_points
*= 12.0f
* 72.0f
;
958 case PPD_CUSTOM_INT
:
959 cparam
->current
.custom_int
= atoi(val
->value
);
962 case PPD_CUSTOM_PASSCODE
:
963 case PPD_CUSTOM_PASSWORD
:
964 case PPD_CUSTOM_STRING
:
965 if (cparam
->current
.custom_string
)
966 _cupsStrFree(cparam
->current
.custom_string
);
968 cparam
->current
.custom_string
= _cupsStrRetain(val
->value
);
973 cupsFreeOptions(num_vals
, vals
);
978 for (i
= o
->num_choices
, c
= o
->choices
; i
> 0; i
--, c
++)
979 if (!_cups_strcasecmp(c
->choice
, choice
))
987 * Option found; mark it and then handle unmarking any other options.
990 if (o
->ui
!= PPD_UI_PICKMANY
)
993 * Unmark all other choices...
996 if ((oldc
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, c
)) != NULL
)
999 cupsArrayRemove(ppd
->marked
, oldc
);
1002 if (!_cups_strcasecmp(option
, "PageSize") || !_cups_strcasecmp(option
, "PageRegion"))
1005 * Mark current page size...
1008 for (j
= 0; j
< ppd
->num_sizes
; j
++)
1009 ppd
->sizes
[j
].marked
= !_cups_strcasecmp(ppd
->sizes
[j
].name
,
1013 * Unmark the current PageSize or PageRegion setting, as
1017 cupsArraySave(ppd
->options
);
1019 if (!_cups_strcasecmp(option
, "PageSize"))
1021 if ((o
= ppdFindOption(ppd
, "PageRegion")) != NULL
)
1024 if ((oldc
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
)) != NULL
)
1027 cupsArrayRemove(ppd
->marked
, oldc
);
1033 if ((o
= ppdFindOption(ppd
, "PageSize")) != NULL
)
1036 if ((oldc
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
)) != NULL
)
1039 cupsArrayRemove(ppd
->marked
, oldc
);
1044 cupsArrayRestore(ppd
->options
);
1046 else if (!_cups_strcasecmp(option
, "InputSlot"))
1049 * Unmark ManualFeed option...
1052 cupsArraySave(ppd
->options
);
1054 if ((o
= ppdFindOption(ppd
, "ManualFeed")) != NULL
)
1057 if ((oldc
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
)) != NULL
)
1060 cupsArrayRemove(ppd
->marked
, oldc
);
1064 cupsArrayRestore(ppd
->options
);
1066 else if (!_cups_strcasecmp(option
, "ManualFeed") &&
1067 !_cups_strcasecmp(choice
, "True"))
1070 * Unmark InputSlot option...
1073 cupsArraySave(ppd
->options
);
1075 if ((o
= ppdFindOption(ppd
, "InputSlot")) != NULL
)
1078 if ((oldc
= (ppd_choice_t
*)cupsArrayFind(ppd
->marked
, &key
)) != NULL
)
1081 cupsArrayRemove(ppd
->marked
, oldc
);
1085 cupsArrayRestore(ppd
->options
);
1091 cupsArrayAdd(ppd
->marked
, c
);