You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1099 lines
27 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
* Option marking routines for CUPS.
*
* Copyright © 2007-2019 by Apple Inc.
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more
* information.
*
* PostScript is a trademark of Adobe Systems, Inc.
*/
/*
* Include necessary headers...
*/
#include "cups-private.h"
#include "ppd-private.h"
#include "debug-internal.h"
/*
* Local functions...
*/
#ifdef DEBUG
static void ppd_debug_marked(ppd_file_t *ppd, const char *title);
#else
# define ppd_debug_marked(ppd,title)
#endif /* DEBUG */
static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
static void ppd_mark_choices(ppd_file_t *ppd, const char *s);
static void ppd_mark_option(ppd_file_t *ppd, const char *option,
const char *choice);
/*
* 'cupsMarkOptions()' - Mark command-line options in a PPD file.
*
* This function maps the IPP "finishings", "media", "mirror",
* "multiple-document-handling", "output-bin", "print-color-mode",
* "print-quality", "printer-resolution", and "sides" attributes to their
* corresponding PPD options and choices.
*/
int /* O - 1 if conflicts exist, 0 otherwise */
cupsMarkOptions(
ppd_file_t *ppd, /* I - PPD file */
int num_options, /* I - Number of options */
cups_option_t *options) /* I - Options */
{
int i, j; /* Looping vars */
char *ptr, /* Pointer into string */
s[255]; /* Temporary string */
const char *val, /* Pointer into value */
*media, /* media option */
*output_bin, /* output-bin option */
*page_size, /* PageSize option */
*ppd_keyword, /* PPD keyword */
*print_color_mode, /* print-color-mode option */
*print_quality, /* print-quality option */
*sides; /* sides option */
cups_option_t *optptr; /* Current option */
ppd_attr_t *attr; /* PPD attribute */
_ppd_cache_t *cache; /* PPD cache and mapping data */
/*
* Check arguments...
*/
if (!ppd || num_options <= 0 || !options)
return (0);
ppd_debug_marked(ppd, "Before...");
/*
* Do special handling for finishings, media, output-bin, output-mode,
* print-color-mode, print-quality, and PageSize...
*/
media = cupsGetOption("media", num_options, options);
output_bin = cupsGetOption("output-bin", num_options, options);
page_size = cupsGetOption("PageSize", num_options, options);
print_quality = cupsGetOption("print-quality", num_options, options);
sides = cupsGetOption("sides", num_options, options);
if ((print_color_mode = cupsGetOption("print-color-mode", num_options,
options)) == NULL)
print_color_mode = cupsGetOption("output-mode", num_options, options);
if ((media || output_bin || print_color_mode || print_quality || sides) &&
!ppd->cache)
{
/*
* Load PPD cache and mapping data as needed...
*/
ppd->cache = _ppdCacheCreateWithPPD(ppd);
}
cache = ppd->cache;
if (media)
{
/*
* Loop through the option string, separating it at commas and marking each
* individual option as long as the corresponding PPD option (PageSize,
* InputSlot, etc.) is not also set.
*
* For PageSize, we also check for an empty option value since some versions
* of macOS use it to specify auto-selection of the media based solely on
* the size.
*/
for (val = media; *val;)
{
/*
* Extract the sub-option from the string...
*/
for (ptr = s; *val && *val != ',' && (size_t)(ptr - s) < (sizeof(s) - 1);)
*ptr++ = *val++;
*ptr++ = '\0';
if (*val == ',')
val ++;
/*
* Mark it...
*/
if (!page_size || !page_size[0])
{
if (!_cups_strncasecmp(s, "Custom.", 7) || ppdPageSize(ppd, s))
ppd_mark_option(ppd, "PageSize", s);
else if ((ppd_keyword = _ppdCacheGetPageSize(cache, NULL, s, NULL)) != NULL)
ppd_mark_option(ppd, "PageSize", ppd_keyword);
}
if (cache && cache->source_option &&
!cupsGetOption(cache->source_option, num_options, options) &&
(ppd_keyword = _ppdCacheGetInputSlot(cache, NULL, s)) != NULL)
ppd_mark_option(ppd, cache->source_option, ppd_keyword);
if (!cupsGetOption("MediaType", num_options, options) &&
(ppd_keyword = _ppdCacheGetMediaType(cache, NULL, s)) != NULL)
ppd_mark_option(ppd, "MediaType", ppd_keyword);
}
}
if (cache)
{
if (!cupsGetOption("com.apple.print.DocumentTicket.PMSpoolFormat",
num_options, options) &&
!cupsGetOption("APPrinterPreset", num_options, options) &&
(print_color_mode || print_quality))
{
/*
* Map output-mode and print-quality to a preset...
*/
_pwg_print_color_mode_t pwg_pcm;/* print-color-mode index */
_pwg_print_quality_t pwg_pq; /* print-quality index */
cups_option_t *preset;/* Current preset option */
if (print_color_mode && !strcmp(print_color_mode, "monochrome"))
pwg_pcm = _PWG_PRINT_COLOR_MODE_MONOCHROME;
else
pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
if (print_quality)
{
pwg_pq = (_pwg_print_quality_t)(atoi(print_quality) - IPP_QUALITY_DRAFT);
if (pwg_pq < _PWG_PRINT_QUALITY_DRAFT)
pwg_pq = _PWG_PRINT_QUALITY_DRAFT;
else if (pwg_pq > _PWG_PRINT_QUALITY_HIGH)
pwg_pq = _PWG_PRINT_QUALITY_HIGH;
}
else
pwg_pq = _PWG_PRINT_QUALITY_NORMAL;
if (cache->num_presets[pwg_pcm][pwg_pq] == 0)
{
/*
* Try to find a preset that works so that we maximize the chances of us
* getting a good print using IPP attributes.
*/
if (cache->num_presets[pwg_pcm][_PWG_PRINT_QUALITY_NORMAL] > 0)
pwg_pq = _PWG_PRINT_QUALITY_NORMAL;
else if (cache->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_pq] > 0)
pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
else
{
pwg_pq = _PWG_PRINT_QUALITY_NORMAL;
pwg_pcm = _PWG_PRINT_COLOR_MODE_COLOR;
}
}
if (cache->num_presets[pwg_pcm][pwg_pq] > 0)
{
/*
* Copy the preset options as long as the corresponding names are not
* already defined in the IPP request...
*/
for (i = cache->num_presets[pwg_pcm][pwg_pq],
preset = cache->presets[pwg_pcm][pwg_pq];
i > 0;
i --, preset ++)
{
if (!cupsGetOption(preset->name, num_options, options))
ppd_mark_option(ppd, preset->name, preset->value);
}
}
}
if (output_bin && !cupsGetOption("OutputBin", num_options, options) &&
(ppd_keyword = _ppdCacheGetOutputBin(cache, output_bin)) != NULL)
{
/*
* Map output-bin to OutputBin...
*/
ppd_mark_option(ppd, "OutputBin", ppd_keyword);
}
if (sides && cache->sides_option &&
!cupsGetOption(cache->sides_option, num_options, options))
{
/*
* Map sides to duplex option...
*/
if (!strcmp(sides, "one-sided") && cache->sides_1sided)
ppd_mark_option(ppd, cache->sides_option, cache->sides_1sided);
else if (!strcmp(sides, "two-sided-long-edge") &&
cache->sides_2sided_long)
ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_long);
else if (!strcmp(sides, "two-sided-short-edge") &&
cache->sides_2sided_short)
ppd_mark_option(ppd, cache->sides_option, cache->sides_2sided_short);
}
}
/*
* Mark other options...
*/
for (i = num_options, optptr = options; i > 0; i --, optptr ++)
{
if (!_cups_strcasecmp(optptr->name, "media") ||
!_cups_strcasecmp(optptr->name, "output-bin") ||
!_cups_strcasecmp(optptr->name, "output-mode") ||
!_cups_strcasecmp(optptr->name, "print-quality") ||
!_cups_strcasecmp(optptr->name, "sides"))
continue;
else if (!_cups_strcasecmp(optptr->name, "resolution") ||
!_cups_strcasecmp(optptr->name, "printer-resolution"))
{
ppd_mark_option(ppd, "Resolution", optptr->value);
ppd_mark_option(ppd, "SetResolution", optptr->value);
/* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
ppd_mark_option(ppd, "JCLResolution", optptr->value);
/* HP */
ppd_mark_option(ppd, "CNRes_PGP", optptr->value);
/* Canon */
}
else if (!_cups_strcasecmp(optptr->name, "multiple-document-handling"))
{
if (!cupsGetOption("Collate", num_options, options) &&
ppdFindOption(ppd, "Collate"))
{
if (_cups_strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
ppd_mark_option(ppd, "Collate", "True");
else
ppd_mark_option(ppd, "Collate", "False");
}
}
else if (!_cups_strcasecmp(optptr->name, "finishings"))
{
/*
* Lookup cupsIPPFinishings attributes for each value...
*/
for (ptr = optptr->value; *ptr;)
{
/*
* Get the next finishings number...
*/
if (!isdigit(*ptr & 255))
break;
if ((j = (int)strtol(ptr, &ptr, 10)) < 3)
break;
/*
* Skip separator as needed...
*/
if (*ptr == ',')
ptr ++;
/*
* Look it up in the PPD file...
*/
sprintf(s, "%d", j);
if ((attr = ppdFindAttr(ppd, "cupsIPPFinishings", s)) == NULL)
continue;
/*
* Apply "*Option Choice" settings from the attribute value...
*/
ppd_mark_choices(ppd, attr->value);
}
}
else if (!_cups_strcasecmp(optptr->name, "APPrinterPreset"))
{
/*
* Lookup APPrinterPreset value...
*/
if ((attr = ppdFindAttr(ppd, "APPrinterPreset", optptr->value)) != NULL)
{
/*
* Apply "*Option Choice" settings from the attribute value...
*/
ppd_mark_choices(ppd, attr->value);
}
}
else if (!_cups_strcasecmp(optptr->name, "mirror"))
ppd_mark_option(ppd, "MirrorPrint", optptr->value);
else
ppd_mark_option(ppd, optptr->name, optptr->value);
}
if (print_quality)
{
int pq = atoi(print_quality); /* print-quaity value */
if (pq == IPP_QUALITY_DRAFT)
ppd_mark_option(ppd, "cupsPrintQuality", "Draft");
else if (pq == IPP_QUALITY_HIGH)
ppd_mark_option(ppd, "cupsPrintQuality", "High");
else
ppd_mark_option(ppd, "cupsPrintQuality", "Normal");
}
ppd_debug_marked(ppd, "After...");
return (ppdConflicts(ppd) > 0);
}
/*
* 'ppdFindChoice()' - Return a pointer to an option choice.
*/
ppd_choice_t * /* O - Choice pointer or @code NULL@ */
ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */
const char *choice) /* I - Name of choice */
{
int i; /* Looping var */
ppd_choice_t *c; /* Current choice */
if (!o || !choice)
return (NULL);
if (choice[0] == '{' || !_cups_strncasecmp(choice, "Custom.", 7))
choice = "Custom";
for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
if (!_cups_strcasecmp(c->choice, choice))
return (c);
return (NULL);
}
/*
* 'ppdFindMarkedChoice()' - Return the marked choice for the specified option.
*/
ppd_choice_t * /* O - Pointer to choice or @code NULL@ */
ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */
const char *option) /* I - Keyword/option name */
{
ppd_choice_t key, /* Search key for choice */
*marked; /* Marked choice */
DEBUG_printf(("2ppdFindMarkedChoice(ppd=%p, option=\"%s\")", ppd, option));
if ((key.option = ppdFindOption(ppd, option)) == NULL)
{
DEBUG_puts("3ppdFindMarkedChoice: Option not found, returning NULL");
return (NULL);
}
marked = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key);
DEBUG_printf(("3ppdFindMarkedChoice: Returning %p(%s)...", marked,
marked ? marked->choice : "NULL"));
return (marked);
}
/*
* 'ppdFindOption()' - Return a pointer to the specified option.
*/
ppd_option_t * /* O - Pointer to option or @code NULL@ */
ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */
const char *option) /* I - Option/Keyword name */
{
/*
* Range check input...
*/
if (!ppd || !option)
return (NULL);
if (ppd->options)
{
/*
* Search in the array...
*/
ppd_option_t key; /* Option search key */
strlcpy(key.keyword, option, sizeof(key.keyword));
return ((ppd_option_t *)cupsArrayFind(ppd->options, &key));
}
else
{
/*
* Search in each group...
*/
int i, j; /* Looping vars */
ppd_group_t *group; /* Current group */
ppd_option_t *optptr; /* Current option */
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
for (j = group->num_options, optptr = group->options;
j > 0;
j --, optptr ++)
if (!_cups_strcasecmp(optptr->keyword, option))
return (optptr);
return (NULL);
}
}
/*
* 'ppdIsMarked()' - Check to see if an option is marked.
*/
int /* O - Non-zero if option is marked */
ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */
const char *option, /* I - Option/Keyword name */
const char *choice) /* I - Choice name */
{
ppd_choice_t key, /* Search key */
*c; /* Choice pointer */
if (!ppd)
return (0);
if ((key.option = ppdFindOption(ppd, option)) == NULL)
return (0);
if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
return (0);
return (!strcmp(c->choice, choice));
}
/*
* 'ppdMarkDefaults()' - Mark all default options in the PPD file.
*/
void
ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */
{
int i; /* Looping variables */
ppd_group_t *g; /* Current group */
ppd_choice_t *c; /* Current choice */
if (!ppd)
return;
/*
* Clean out the marked array...
*/
for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
c;
c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
{
cupsArrayRemove(ppd->marked, c);
c->marked = 0;
}
/*
* Then repopulate it with the defaults...
*/
for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
ppd_defaults(ppd, g);
/*
* Finally, tag any conflicts (API compatibility) once at the end.
*/
ppdConflicts(ppd);
}
/*
* 'ppdMarkOption()' - Mark an option in a PPD file and return the number of
* conflicts.
*/
int /* O - Number of conflicts */
ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */
const char *option, /* I - Keyword */
const char *choice) /* I - Option name */
{
DEBUG_printf(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")",
ppd, option, choice));
/*
* Range check input...
*/
if (!ppd || !option || !choice)
return (0);
/*
* Mark the option...
*/
ppd_mark_option(ppd, option, choice);
/*
* Return the number of conflicts...
*/
return (ppdConflicts(ppd));
}
/*
* 'ppdFirstOption()' - Return the first option in the PPD file.
*
* Options are returned from all groups in ascending alphanumeric order.
*
* @since CUPS 1.2/macOS 10.5@
*/
ppd_option_t * /* O - First option or @code NULL@ */
ppdFirstOption(ppd_file_t *ppd) /* I - PPD file */
{
if (!ppd)
return (NULL);
else
return ((ppd_option_t *)cupsArrayFirst(ppd->options));
}
/*
* 'ppdNextOption()' - Return the next option in the PPD file.
*
* Options are returned from all groups in ascending alphanumeric order.
*
* @since CUPS 1.2/macOS 10.5@
*/
ppd_option_t * /* O - Next option or @code NULL@ */
ppdNextOption(ppd_file_t *ppd) /* I - PPD file */
{
if (!ppd)
return (NULL);
else
return ((ppd_option_t *)cupsArrayNext(ppd->options));
}
/*
* '_ppdParseOptions()' - Parse options from a PPD file.
*
* This function looks for strings of the form:
*
* *option choice ... *optionN choiceN
* property value ... propertyN valueN
*
* It stops when it finds a string that doesn't match this format.
*/
int /* O - Number of options */
_ppdParseOptions(
const char *s, /* I - String to parse */
int num_options, /* I - Number of options */
cups_option_t **options, /* IO - Options */
_ppd_parse_t which) /* I - What to parse */
{
char option[PPD_MAX_NAME * 2 + 1], /* Current option/property */
choice[PPD_MAX_NAME], /* Current choice/value */
*ptr; /* Pointer into option or choice */
if (!s)
return (num_options);
/*
* Read all of the "*Option Choice" and "property value" pairs from the
* string, add them to an options array as we go...
*/
while (*s)
{
/*
* Skip leading whitespace...
*/
while (_cups_isspace(*s))
s ++;
/*
* Get the option/property name...
*/
ptr = option;
while (*s && !_cups_isspace(*s) && ptr < (option + sizeof(option) - 1))
*ptr++ = *s++;
if (ptr == s || !_cups_isspace(*s))
break;
*ptr = '\0';
/*
* Get the choice...
*/
while (_cups_isspace(*s))
s ++;
if (!*s)
break;
ptr = choice;
while (*s && !_cups_isspace(*s) && ptr < (choice + sizeof(choice) - 1))
*ptr++ = *s++;
if (*s && !_cups_isspace(*s))
break;
*ptr = '\0';
/*
* Add it to the options array...
*/
if (option[0] == '*' && which != _PPD_PARSE_PROPERTIES)
num_options = cupsAddOption(option + 1, choice, num_options, options);
else if (option[0] != '*' && which != _PPD_PARSE_OPTIONS)
num_options = cupsAddOption(option, choice, num_options, options);
}
return (num_options);
}
#ifdef DEBUG
/*
* 'ppd_debug_marked()' - Output the marked array to stdout...
*/
static void
ppd_debug_marked(ppd_file_t *ppd, /* I - PPD file data */
const char *title) /* I - Title for list */
{
ppd_choice_t *c; /* Current choice */
DEBUG_printf(("2cupsMarkOptions: %s", title));
for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
c;
c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
DEBUG_printf(("2cupsMarkOptions: %s=%s", c->option->keyword, c->choice));
}
#endif /* DEBUG */
/*
* 'ppd_defaults()' - Set the defaults for this group and all sub-groups.
*/
static void
ppd_defaults(ppd_file_t *ppd, /* I - PPD file */
ppd_group_t *g) /* I - Group to default */
{
int i; /* Looping var */
ppd_option_t *o; /* Current option */
ppd_group_t *sg; /* Current sub-group */
for (i = g->num_options, o = g->options; i > 0; i --, o ++)
if (_cups_strcasecmp(o->keyword, "PageRegion") != 0)
ppd_mark_option(ppd, o->keyword, o->defchoice);
for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++)
ppd_defaults(ppd, sg);
}
/*
* 'ppd_mark_choices()' - Mark one or more option choices from a string.
*/
static void
ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
const char *s) /* I - "*Option Choice ..." string */
{
int i, /* Looping var */
num_options; /* Number of options */
cups_option_t *options, /* Options */
*option; /* Current option */
if (!s)
return;
options = NULL;
num_options = _ppdParseOptions(s, 0, &options, 0);
for (i = num_options, option = options; i > 0; i --, option ++)
ppd_mark_option(ppd, option->name, option->value);
cupsFreeOptions(num_options, options);
}
/*
* 'ppd_mark_option()' - Quick mark an option without checking for conflicts.
*/
static void
ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */
const char *option, /* I - Option name */
const char *choice) /* I - Choice name */
{
int i, j; /* Looping vars */
ppd_option_t *o; /* Option pointer */
ppd_choice_t *c, /* Choice pointer */
*oldc, /* Old choice pointer */
key; /* Search key for choice */
struct lconv *loc; /* Locale data */
DEBUG_printf(("7ppd_mark_option(ppd=%p, option=\"%s\", choice=\"%s\")",
ppd, option, choice));
/*
* AP_D_InputSlot is the "default input slot" on macOS, and setting
* it clears the regular InputSlot choices...
*/
if (!_cups_strcasecmp(option, "AP_D_InputSlot"))
{
cupsArraySave(ppd->options);
if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
{
key.option = o;
if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
{
oldc->marked = 0;
cupsArrayRemove(ppd->marked, oldc);
}
}
cupsArrayRestore(ppd->options);
}
/*
* Check for custom options...
*/
cupsArraySave(ppd->options);
o = ppdFindOption(ppd, option);
cupsArrayRestore(ppd->options);
if (!o)
return;
loc = localeconv();
if (!_cups_strncasecmp(choice, "Custom.", 7))
{
/*
* Handle a custom option...
*/
if ((c = ppdFindChoice(o, "Custom")) == NULL)
return;
if (!_cups_strcasecmp(option, "PageSize"))
{
/*
* Handle custom page sizes...
*/
ppdPageSize(ppd, choice);
}
else
{
/*
* Handle other custom options...
*/
ppd_coption_t *coption; /* Custom option */
ppd_cparam_t *cparam; /* Custom parameter */
char *units; /* Custom points units */
if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
{
if ((cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params)) == NULL)
return;
switch (cparam->type)
{
case PPD_CUSTOM_UNKNOWN :
break;
case PPD_CUSTOM_CURVE :
case PPD_CUSTOM_INVCURVE :
case PPD_CUSTOM_REAL :
cparam->current.custom_real = (float)_cupsStrScand(choice + 7,
NULL, loc);
break;
case PPD_CUSTOM_POINTS :
cparam->current.custom_points = (float)_cupsStrScand(choice + 7,
&units,
loc);
if (units)
{
if (!_cups_strcasecmp(units, "cm"))
cparam->current.custom_points *= 72.0f / 2.54f;
else if (!_cups_strcasecmp(units, "mm"))
cparam->current.custom_points *= 72.0f / 25.4f;
else if (!_cups_strcasecmp(units, "m"))
cparam->current.custom_points *= 72.0f / 0.0254f;
else if (!_cups_strcasecmp(units, "in"))
cparam->current.custom_points *= 72.0f;
else if (!_cups_strcasecmp(units, "ft"))
cparam->current.custom_points *= 12.0f * 72.0f;
}
break;
case PPD_CUSTOM_INT :
cparam->current.custom_int = atoi(choice + 7);
break;
case PPD_CUSTOM_PASSCODE :
case PPD_CUSTOM_PASSWORD :
case PPD_CUSTOM_STRING :
if (cparam->current.custom_string)
free(cparam->current.custom_string);
cparam->current.custom_string = strdup(choice + 7);
break;
}
}
}
/*
* Make sure that we keep the option marked below...
*/
choice = "Custom";
}
else if (choice[0] == '{')
{
/*
* Handle multi-value custom options...
*/
ppd_coption_t *coption; /* Custom option */
ppd_cparam_t *cparam; /* Custom parameter */
char *units; /* Custom points units */
int num_vals; /* Number of values */
cups_option_t *vals, /* Values */
*val; /* Value */
if ((c = ppdFindChoice(o, "Custom")) == NULL)
return;
if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
{
num_vals = cupsParseOptions(choice, 0, &vals);
for (i = 0, val = vals; i < num_vals; i ++, val ++)
{
if ((cparam = ppdFindCustomParam(coption, val->name)) == NULL)
continue;
switch (cparam->type)
{
case PPD_CUSTOM_UNKNOWN :
break;
case PPD_CUSTOM_CURVE :
case PPD_CUSTOM_INVCURVE :
case PPD_CUSTOM_REAL :
cparam->current.custom_real = (float)_cupsStrScand(val->value,
NULL, loc);
break;
case PPD_CUSTOM_POINTS :
cparam->current.custom_points = (float)_cupsStrScand(val->value,
&units,
loc);
if (units)
{
if (!_cups_strcasecmp(units, "cm"))
cparam->current.custom_points *= 72.0f / 2.54f;
else if (!_cups_strcasecmp(units, "mm"))
cparam->current.custom_points *= 72.0f / 25.4f;
else if (!_cups_strcasecmp(units, "m"))
cparam->current.custom_points *= 72.0f / 0.0254f;
else if (!_cups_strcasecmp(units, "in"))
cparam->current.custom_points *= 72.0f;
else if (!_cups_strcasecmp(units, "ft"))
cparam->current.custom_points *= 12.0f * 72.0f;
}
break;
case PPD_CUSTOM_INT :
cparam->current.custom_int = atoi(val->value);
break;
case PPD_CUSTOM_PASSCODE :
case PPD_CUSTOM_PASSWORD :
case PPD_CUSTOM_STRING :
if (cparam->current.custom_string)
free(cparam->current.custom_string);
cparam->current.custom_string = strdup(val->value);
break;
}
}
cupsFreeOptions(num_vals, vals);
}
}
else
{
for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
if (!_cups_strcasecmp(c->choice, choice))
break;
if (!i)
return;
}
/*
* Option found; mark it and then handle unmarking any other options.
*/
if (o->ui != PPD_UI_PICKMANY)
{
/*
* Unmark all other choices...
*/
if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
{
oldc->marked = 0;
cupsArrayRemove(ppd->marked, oldc);
}
if (!_cups_strcasecmp(option, "PageSize") || !_cups_strcasecmp(option, "PageRegion"))
{
/*
* Mark current page size...
*/
for (j = 0; j < ppd->num_sizes; j ++)
ppd->sizes[j].marked = !_cups_strcasecmp(ppd->sizes[j].name,
choice);
/*
* Unmark the current PageSize or PageRegion setting, as
* appropriate...
*/
cupsArraySave(ppd->options);
if (!_cups_strcasecmp(option, "PageSize"))
{
if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
{
key.option = o;
if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
{
oldc->marked = 0;
cupsArrayRemove(ppd->marked, oldc);
}
}
}
else
{
if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
{
key.option = o;
if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
{
oldc->marked = 0;
cupsArrayRemove(ppd->marked, oldc);
}
}
}
cupsArrayRestore(ppd->options);
}
else if (!_cups_strcasecmp(option, "InputSlot"))
{
/*
* Unmark ManualFeed option...
*/
cupsArraySave(ppd->options);
if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
{
key.option = o;
if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
{
oldc->marked = 0;
cupsArrayRemove(ppd->marked, oldc);
}
}
cupsArrayRestore(ppd->options);
}
else if (!_cups_strcasecmp(option, "ManualFeed") &&
!_cups_strcasecmp(choice, "True"))
{
/*
* Unmark InputSlot option...
*/
cupsArraySave(ppd->options);
if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
{
key.option = o;
if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
{
oldc->marked = 0;
cupsArrayRemove(ppd->marked, oldc);
}
}
cupsArrayRestore(ppd->options);
}
}
c->marked = 1;
cupsArrayAdd(ppd->marked, c);
}