blob: c0fdc911d62181669919aa391ac611e43559826d [file] [log] [blame]
/*
* "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $"
*
* Option marking routines for the Common UNIX Printing System (CUPS).
*
* Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
* which should have been included with this file. If this file is
* file is missing or damaged, see the license at "http://www.cups.org/".
*
* PostScript is a trademark of Adobe Systems, Inc.
*
* This file is subject to the Apple OS-Developed Software exception.
*
* Contents:
*
* cupsMarkOptions() - Mark command-line options in a PPD file.
* ppdConflicts() - Check to see if there are any conflicts among the
* marked option choices.
* ppdFindChoice() - Return a pointer to an option choice.
* ppdFindMarkedChoice() - Return the marked choice for the specified option.
* ppdFindOption() - Return a pointer to the specified option.
* ppdIsMarked() - Check to see if an option is marked.
* ppdMarkDefaults() - Mark all default options in the PPD file.
* ppdMarkOption() - Mark an option in a PPD file.
* ppdFirstOption() - Return the first option in the PPD file.
* ppdNextOption() - Return the next option in the PPD file.
* debug_marked() - Output the marked array to stdout...
* ppd_defaults() - Set the defaults for this group and all sub-groups.
* ppd_mark_choices() - Mark one or more option choices from a string.
*/
/*
* Include necessary headers...
*/
#include "cups.h"
#include "string.h"
#include "debug.h"
/*
* Local functions...
*/
#ifdef DEBUG
static void debug_marked(ppd_file_t *ppd, const char *title);
#else
# define debug_marked(ppd,title)
#endif /* DEBUG */
static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
static int ppd_mark_choices(ppd_file_t *ppd, const char *options);
/*
* 'cupsMarkOptions()' - Mark command-line options in a PPD file.
*
* This function maps the IPP "finishings", "media", "mirror",
* "multiple-document-handling", "output-bin", "printer-resolution", and
* "sides" attributes to their corresponding PPD options and choices.
*/
int /* O - 1 if conflicting */
cupsMarkOptions(
ppd_file_t *ppd, /* I - PPD file */
int num_options, /* I - Number of options */
cups_option_t *options) /* I - Options */
{
int i, j, k; /* Looping vars */
int conflict; /* Option conflicts */
char *val, /* Pointer into value */
*ptr, /* Pointer into string */
s[255]; /* Temporary string */
const char *page_size; /* PageSize option */
cups_option_t *optptr; /* Current option */
ppd_option_t *option; /* PPD option */
ppd_attr_t *attr; /* PPD attribute */
static const char * const duplex_options[] =
{ /* Duplex option names */
"Duplex", /* Adobe */
"EFDuplex", /* EFI */
"EFDuplexing", /* EFI */
"KD03Duplex", /* Kodak */
"JCLDuplex" /* Samsung */
};
static const char * const duplex_one[] =
{ /* one-sided names */
"None",
"False"
};
static const char * const duplex_two_long[] =
{ /* two-sided-long-edge names */
"DuplexNoTumble", /* Adobe */
"LongEdge", /* EFI */
"Top" /* EFI */
};
static const char * const duplex_two_short[] =
{ /* two-sided-long-edge names */
"DuplexTumble", /* Adobe */
"ShortEdge", /* EFI */
"Bottom" /* EFI */
};
/*
* Check arguments...
*/
if (!ppd || num_options <= 0 || !options)
return (0);
debug_marked(ppd, "Before...");
/*
* Mark options...
*/
conflict = 0;
for (i = num_options, optptr = options; i > 0; i --, optptr ++)
if (!strcasecmp(optptr->name, "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 X use it to specify auto-selection
* of the media based solely on the size.
*/
page_size = cupsGetOption("PageSize", num_options, options);
for (val = optptr->value; *val;)
{
/*
* Extract the sub-option from the string...
*/
for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);)
*ptr++ = *val++;
*ptr++ = '\0';
if (*val == ',')
val ++;
/*
* Mark it...
*/
if (!page_size || !page_size[0])
if (ppdMarkOption(ppd, "PageSize", s))
conflict = 1;
if (cupsGetOption("InputSlot", num_options, options) == NULL)
if (ppdMarkOption(ppd, "InputSlot", s))
conflict = 1;
if (cupsGetOption("MediaType", num_options, options) == NULL)
if (ppdMarkOption(ppd, "MediaType", s))
conflict = 1;
if (cupsGetOption("EFMediaType", num_options, options) == NULL)
if (ppdMarkOption(ppd, "EFMediaType", s)) /* EFI */
conflict = 1;
if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL)
if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */
conflict = 1;
if (strcasecmp(s, "manual") == 0 &&
cupsGetOption("ManualFeed", num_options, options) == NULL)
if (ppdMarkOption(ppd, "ManualFeed", "True"))
conflict = 1;
}
}
else if (!strcasecmp(optptr->name, "sides"))
{
for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
if (cupsGetOption(duplex_options[j], num_options, options) != NULL)
break;
if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
{
/*
* Don't override the PPD option with the IPP attribute...
*/
continue;
}
if (!strcasecmp(optptr->value, "one-sided"))
{
/*
* Mark the appropriate duplex option for one-sided output...
*/
for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
break;
if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
{
for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++)
if (ppdFindChoice(option, duplex_one[k]))
{
if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k]))
conflict = 1;
break;
}
}
}
else if (!strcasecmp(optptr->value, "two-sided-long-edge"))
{
/*
* Mark the appropriate duplex option for two-sided-long-edge output...
*/
for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
break;
if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
{
for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++)
if (ppdFindChoice(option, duplex_two_long[k]))
{
if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k]))
conflict = 1;
break;
}
}
}
else if (!strcasecmp(optptr->value, "two-sided-short-edge"))
{
/*
* Mark the appropriate duplex option for two-sided-short-edge output...
*/
for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++)
if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL)
break;
if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])))
{
for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++)
if (ppdFindChoice(option, duplex_two_short[k]))
{
if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k]))
conflict = 1;
break;
}
}
}
}
else if (!strcasecmp(optptr->name, "resolution") ||
!strcasecmp(optptr->name, "printer-resolution"))
{
if (ppdMarkOption(ppd, "Resolution", optptr->value))
conflict = 1;
if (ppdMarkOption(ppd, "SetResolution", optptr->value))
/* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */
conflict = 1;
if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */
conflict = 1;
if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */
conflict = 1;
}
else if (!strcasecmp(optptr->name, "output-bin"))
{
if (!cupsGetOption("OutputBin", num_options, options))
if (ppdMarkOption(ppd, "OutputBin", optptr->value))
conflict = 1;
}
else if (!strcasecmp(optptr->name, "multiple-document-handling"))
{
if (!cupsGetOption("Collate", num_options, options) &&
ppdFindOption(ppd, "Collate"))
{
if (strcasecmp(optptr->value, "separate-documents-uncollated-copies"))
{
if (ppdMarkOption(ppd, "Collate", "True"))
conflict = 1;
}
else
{
if (ppdMarkOption(ppd, "Collate", "False"))
conflict = 1;
}
}
}
else if (!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 = 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...
*/
if (ppd_mark_choices(ppd, attr->value))
conflict = 1;
}
}
else if (!strcasecmp(optptr->name, "mirror"))
{
if (ppdMarkOption(ppd, "MirrorPrint", optptr->value))
conflict = 1;
}
else if (ppdMarkOption(ppd, optptr->name, optptr->value))
conflict = 1;
debug_marked(ppd, "After...");
return (conflict);
}
/*
* 'ppdConflicts()' - Check to see if there are any conflicts among the
* marked option choices.
*
* The returned value is the same as returned by @link ppdMarkOption@.
*/
int /* O - Number of conflicts found */
ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */
{
int i, /* Looping variable */
conflicts; /* Number of conflicts */
ppd_const_t *c; /* Current constraint */
ppd_option_t *o1, *o2; /* Options */
ppd_choice_t *c1, *c2; /* Choices */
ppd_choice_t key; /* Search key */
if (!ppd)
return (0);
/*
* Clear all conflicts...
*/
conflicts = 0;
for (o1 = ppdFirstOption(ppd); o1; o1 = ppdNextOption(ppd))
o1->conflicted = 0;
cupsArraySave(ppd->marked);
/*
* Loop through all of the UI constraints and flag any options
* that conflict...
*/
for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
i > 0;
i --, c ++)
{
/*
* Grab pointers to the first option...
*/
if (!o1 || strcmp(c->option1, o1->keyword))
{
o1 = ppdFindOption(ppd, c->option1);
c1 = NULL;
}
if (!o1)
continue;
else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
{
/*
* This constraint maps to a specific choice.
*/
key.option = o1;
if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
(!c1->marked || strcmp(c->choice1, c1->choice)))
c1 = NULL;
}
else if (!c1)
{
/*
* This constraint applies to any choice for this option.
*/
key.option = o1;
if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
(!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") ||
!strcasecmp(c1->choice, "False")))
c1 = NULL;
}
/*
* Grab pointers to the second option...
*/
if (!o2 || strcmp(c->option2, o2->keyword))
{
o2 = ppdFindOption(ppd, c->option2);
c2 = NULL;
}
if (!o2)
continue;
else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
{
/*
* This constraint maps to a specific choice.
*/
key.option = o2;
if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
(!c2->marked || strcmp(c->choice2, c2->choice)))
c2 = NULL;
}
else if (!c2)
{
/*
* This constraint applies to any choice for this option.
*/
key.option = o2;
if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
(!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") ||
!strcasecmp(c2->choice, "False")))
c2 = NULL;
}
/*
* If both options are marked then there is a conflict...
*/
if (c1 && c1->marked && c2 && c2->marked)
{
DEBUG_printf(("%s->%s conflicts with %s->%s (%s %s %s %s)\n",
o1->keyword, c1->choice, o2->keyword, c2->choice,
c->option1, c->choice1, c->option2, c->choice2));
conflicts ++;
o1->conflicted = 1;
o2->conflicted = 1;
}
}
cupsArrayRestore(ppd->marked);
/*
* Return the number of conflicts found...
*/
return (conflicts);
}
/*
* '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 == NULL || choice == NULL)
return (NULL);
for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
if (strcasecmp(c->choice, choice) == 0)
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 */
if ((key.option = ppdFindOption(ppd, option)) == NULL)
return (NULL);
return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
}
/*
* '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 (!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);
/*
* Then repopulate it with the defaults...
*/
for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
ppd_defaults(ppd, g);
}
/*
* 'ppdMarkOption()' - Mark an option in a PPD file.
*/
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 */
{
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(("ppdMarkOption(ppd=%p, option=\"%s\", choice=\"%s\")\n",
ppd, option, choice));
/*
* Range check input...
*/
if (!ppd || !option || !choice)
return (0);
/*
* AP_D_InputSlot is the "default input slot" on MacOS X, and setting
* it clears the regular InputSlot choices...
*/
if (!strcasecmp(option, "AP_D_InputSlot"))
{
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);
}
}
}
/*
* Check for custom options...
*/
if ((o = ppdFindOption(ppd, option)) == NULL)
return (0);
loc = localeconv();
if (!strncasecmp(choice, "Custom.", 7))
{
/*
* Handle a custom option...
*/
if ((c = ppdFindChoice(o, "Custom")) == NULL)
return (0);
if (!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 (0);
switch (cparam->type)
{
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 (!strcasecmp(units, "cm"))
cparam->current.custom_points *= 72.0f / 2.54f;
else if (!strcasecmp(units, "mm"))
cparam->current.custom_points *= 72.0f / 25.4f;
else if (!strcasecmp(units, "m"))
cparam->current.custom_points *= 72.0f / 0.0254f;
else if (!strcasecmp(units, "in"))
cparam->current.custom_points *= 72.0f;
else if (!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)
_cupsStrFree(cparam->current.custom_string);
cparam->current.custom_string = _cupsStrAlloc(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 (0);
if ((coption = ppdFindCustomOption(ppd, option)) != NULL)
{
num_vals = cupsParseOptions(choice + 1, 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_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 (!strcasecmp(units, "cm"))
cparam->current.custom_points *= 72.0f / 2.54f;
else if (!strcasecmp(units, "mm"))
cparam->current.custom_points *= 72.0f / 25.4f;
else if (!strcasecmp(units, "m"))
cparam->current.custom_points *= 72.0f / 0.0254f;
else if (!strcasecmp(units, "in"))
cparam->current.custom_points *= 72.0f;
else if (!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)
_cupsStrFree(cparam->current.custom_string);
cparam->current.custom_string = _cupsStrAlloc(val->value);
break;
}
}
cupsFreeOptions(num_vals, vals);
}
}
else
{
for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
if (!strcasecmp(c->choice, choice))
break;
if (!i)
return (0);
}
/*
* 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 (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
{
/*
* Mark current page size...
*/
for (j = 0; j < ppd->num_sizes; j ++)
ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
choice);
/*
* Unmark the current PageSize or PageRegion setting, as
* appropriate...
*/
if (!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);
}
}
}
}
else if (!strcasecmp(option, "InputSlot"))
{
/*
* Unmark ManualFeed option...
*/
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);
}
}
}
else if (!strcasecmp(option, "ManualFeed") &&
!strcasecmp(choice, "True"))
{
/*
* Unmark InputSlot option...
*/
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);
}
}
}
}
c->marked = 1;
cupsArrayAdd(ppd->marked, c);
/*
* 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@
*/
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@
*/
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));
}
#ifdef DEBUG
/*
* 'debug_marked()' - Output the marked array to stdout...
*/
static void
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(("cupsMarkOptions: %s\n", title));
for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
c;
c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
DEBUG_printf(("cupsMarkOptions: %s=%s\n", 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 (strcasecmp(o->keyword, "PageRegion") != 0)
ppdMarkOption(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 int /* O - 1 if there are conflicts, 0 otherwise */
ppd_mark_choices(ppd_file_t *ppd, /* I - PPD file */
const char *options) /* I - "*Option Choice ..." string */
{
char option[PPD_MAX_NAME], /* Current option */
choice[PPD_MAX_NAME], /* Current choice */
*ptr; /* Pointer into option or choice */
int conflict = 0; /* Do we have a conflict? */
if (!options)
return (0);
/*
* Read all of the "*Option Choice" pairs from the string, marking PPD
* options as we go...
*/
while (*options)
{
/*
* Skip leading whitespace...
*/
while (isspace(*options & 255))
options ++;
if (*options != '*')
break;
/*
* Get the option name...
*/
options ++;
ptr = option;
while (*options && !isspace(*options & 255) &&
ptr < (option + sizeof(option) - 1))
*ptr++ = *options++;
if (ptr == option)
break;
*ptr = '\0';
/*
* Get the choice...
*/
while (isspace(*options & 255))
options ++;
if (!*options)
break;
ptr = choice;
while (*options && !isspace(*options & 255) &&
ptr < (choice + sizeof(choice) - 1))
*ptr++ = *options++;
*ptr = '\0';
/*
* Mark the option...
*/
if (ppdMarkOption(ppd, option, choice))
conflict = 1;
}
/*
* Return whether we had any conflicts...
*/
return (conflict);
}
/*
* End of "$Id: mark.c 7278 2008-01-31 01:23:09Z mike $".
*/